Thí nghiệm 1: Mô phỏng Giao diện người dùng đơn giản
Bài tập này yêu cầu xây dựng một hệ thống GUI đơn giản bằng cách sử dụng mối quan hệ kết hợp giữa các lớp.
// task1.cpp
#include "CuaSo.hpp"
#include <iostream>
void kiemTra() {
CuaSo cuaSo("Demo");
cuaSo.themNutBam("them");
cuaSo.themNutBam("xoa");
cuaSo.themNutBam("sua");
cuaSo.themNutBam("them");
cuaSo.hienThi();
cuaSo.dongCuaSo();
}
int main() {
std::cout << "Dùng lớp kết hợp để mô phỏng GUI đơn giản:
";
kiemTra();
}
// CuaSo.hpp
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
#include "NutBam.hpp"
class CuaSo {
public:
CuaSo(const std::string& tieuDe_);
void hienThi() const;
void dongCuaSo();
void themNutBam(const std::string& nhan);
void clickNutBam(const std::string& nhan);
private:
bool coNutBam(const std::string& nhan) const;
private:
std::string tieuDe;
std::vector<NutBam> danhSachNútBấm;
};
CuaSo::CuaSo(const std::string& tieuDe_) : tieuDe{ tieuDe_ } {
danhSachNútBấm.emplace_back("dong");
}
inline void CuaSo::hienThi() const {
std::string s(40, '*');
std::cout << s << std::endl;
std::cout << "cua so : " << tieuDe << std::endl;
int stt = 0;
for (const auto& nutBam : danhSachNútBấm)
std::cout << ++stt << ". " << nutBam.layNhan() << std::endl;
std::cout << s << std::endl;
}
inline void CuaSo::dongCuaSo() {
std::cout << "dong cua so '" << tieuDe << "'" << std::endl;
clickNutBam("dong");
}
inline bool CuaSo::coNutBam(const std::string& nhan) const {
for (const auto& nutBam : danhSachNútBấm)
if (nutBam.layNhan() == nhan)
return true;
return false;
}
inline void CuaSo::themNutBam(const std::string& nhan) {
if (coNutBam(nhan))
std::cout << "nut bam " << nhan << " da ton tai!
";
else
danhSachNútBấm.emplace_back(nhan);
}
inline void CuaSo::clickNutBam(const std::string& nhan) {
for (auto& nutBam : danhSachNútBấm)
if (nutBam.layNhan() == nhan) {
nutBam.click();
return;
}
std::cout << "khong tim thay nut bam: " << nhan << std::endl;
}
// NutBam.hpp
#pragma once
#include <iostream>
#include<string>
class NutBam {
public:
NutBam(const std::string& nhan_);
const std::string& layNhan() const;
void click();
private:
std::string nhan;
};
NutBam::NutBam(const std::string& nhan_) :nhan{ nhan_ } {}
inline const std::string& NutBam::layNhan()const {
return nhan;
}
inline void NutBam::click() {
std::cout << "Nut bam '" << nhan << "' duoc click
";
}
Câu hỏi và trả lời
Câu 1: Lớp `CuaSo` và `NutBam` có mối quan hệ kết hợp. `NutBam` được kết hợp trong `CuaSo` dưới dạng một mảng động.
Câu 2: Ưu điểm: Phương thức `coNutBam` cho phép truy vấn trực tiếp xem cửa sổ có chứa một nút bấm cụ thể hay không, làm cho việc truy vấn trở nên tiện lợi và trực quan, tăng tính linh hoạt của giao diện. Nhược điểm: Việc công khai phương thức nội bộ của lớp cho bên ngoài có thể dẫn đến rủi ro. Nếu các nhà phát triển bên ngoài dựa vào giao diện này để thực hiện các thao tác, bất kỳ thay đổi nào trong nội bộ giao diện đó có thể ảnh hưởng đến tất cả mã nguồn bên ngoài.
Một lớp nên thiết lập các phương thức cần thiết cho người dùng là công khai. Nếu một số phương thức và dữ liệu tạm thời chỉ cần được gọi nội bộ hoặc liên quan đến việc sửa đổi trạng thái đối tượng, chúng nên được đặt ở chế độ riêng tư để ngăn người dùng thao tác sai dẫn đến sự cố hệ thống hoặc bị xâm nhập độc hại.
Thí nghiệm 2: So sánh sao chép sâu với `std::vector`
Bài tập này kiểm tra sự khác biệt giữa sao chép sâu và các thao tác trên `std::vector`.
// kiemTraSaoChep.cpp
#include <iostream>
#include <vector>
void kiemTra1();
void kiemTra2();
void hienThiVector1(const std::vector<int>& v);
void hienThiVector2(const std::vector<int>& v);
void hienThiVector2Chieu(const std::vector& v);
int main()
{
std::cout << "Kiểm tra sao chép sâu 1: vector<int> chuẩn
";
kiemTra1();
std::cout << "
Kiểm tra sao chép sâu 2: vector<int> lồng nhau
";
kiemTra2();
}
void kiemTra1()
{
std::vector<int> vector1(5, 42);
const std::vector<int> vector2(vector1);
std::cout << "Sau khi khoi tao copy:";
std::cout << "vector1 : "; hienThiVector1(vector1);
std::cout << "vector2 : "; hienThiVector1(vector2);
vector1.at(0) = -1;
std::cout << "Sau khi sua vector1[0]";
std::cout << "vector1 = "; hienThiVector1(vector1);
std::cout << "vector2 = "; hienThiVector1(vector2);
}
void kiemTra2()
{
std::vector vector1{ {1,2,3},{4,5,6,7} };
const std::vector vector2(vector1);
std::cout << "Sau khi khoi tao copy:";
std::cout << "vector1 : "; hienThiVector2Chieu(vector1);
std::cout << "vector2 : "; hienThiVector2Chieu(vector2);
vector1.at(0).push_back(-1);
std::cout << "Sau khi sua vector1[0]";
std::cout << "vector1 :
"; hienThiVector2Chieu(vector1);
std::cout << "vector2 :
"; hienThiVector2Chieu(vector2);
}
void hienThiVector1(const std::vector<int>& v)
{
if (v.size() == 0)
{
std::cout << '
';
return;
}
std::cout << v.at(0);
for (auto i = 1; i < v.size(); i++)
std::cout << ", " << v.at(i);
std::cout << '
';
}
void hienThiVector2(const std::vector<int>& v) {
if (v.size() == 0)
{
std::cout << '
';
return;
}
auto it = v.begin();
std::cout << *it;
for (it = v.begin() + 1; it != v.end(); it++)
std::cout << "," << *it;
std::cout << '
';
}
void hienThiVector2Chieu(const std::vector& v)
{
if (v.size() == 0)
{
std::cout << '
';
return;
}
for (auto& i : v)
hienThiVector2(i);
}
Câu hỏi và trả lời
Câu 1:
- `std::vector
vector1(5, 42);` là một hàm tạo, tạo một vector có 5 phần tử, mỗi phần tử có giá trị là 42. - `const std::vector
vector2(vector1);` là hàm tạo sao chép, khởi tạo `vector2` bằng `vector1`. - Ban đầu, `vector1` và `vector2` mỗi cái chứa 5 mục dữ liệu có giá trị là 42.
Câu 2: `vector1.size() = 2`, `vector2.size() = 2`, `vector1[0].size() = 3`
Câu 3: Việc viết `vector1.at(0) = -1` thành `vector1[0] = -1` có thể đạt được hiệu quả sửa đổi tương tự. Sự khác biệt cốt lõi nằm ở việc kiểm tra giới hạn: `at()` sẽ kiểm tra giới hạn và ném một ngoại lệ nếu truy cập không hợp lệ, trong khi `operator[]` không kiểm tra, hành vi truy cập ngoài giới hạn là không xác định.
Câu 4:
- (1) Có thể xuất ra -1. Bởi vì tham chiếu `r` được liên kết với vector con đầu tiên của `vector1`, sau khi `push_back(-1)`, việc truy cập phần tử cuối cùng của nó qua `r` tự nhiên sẽ là -1 vừa được thêm vào.
- (2) Sử dụng `const&` để nhận giá trị trả về có ưu điểm là tránh sao chép đối tượng không cần thiết, tiết kiệm bộ nhớ và chi phí khởi tạo; hạn chế là không thể sửa đổi đối tượng được tham chiếu thông qua tham chiếu đó.
Câu 5:
- (1) Hàm tạo sao chép của vector chuẩn thực hiện sao chép sâu. Bằng chứng là sau khi sửa đổi nội dung của `vector1`, `vector2` vẫn không thay đổi, cho thấy dữ liệu của cả hai là hoàn toàn độc lập.
- (2) Phương thức `at()` phải cung cấp phiên bản `const`. Bởi vì khi `v` là vector
thông thường, `v.at(0)` trả về `int&` (có thể sửa đổi); khi `v` là `const vector `, `v.at(0)` phải trả về `const int&` (chỉ đọc), để đảm bảo tính đúng đắn của ngữ nghĩa truy cập đối tượng `const`.
Thí nghiệm 3: Xây dựng lớp `VectorNguyen` tùy chỉnh
Bài tập này yêu cầu triển khai một lớp vector nguyên tùy chỉnh để quản lý bộ nhớ động.
// VectorNguyen.hpp
#pragma once
#include <iostream>
#include <algorithm>
class VectorNguyen {
public:
VectorNguyen();
VectorNguyen(int soLuong);
VectorNguyen(int soLuong, int giaTri);
VectorNguyen(const VectorNguyen& vectorX);
~VectorNguyen();
int kichThuoc() const;
int& tai(int chiSo);
const int& tai(int chiSo) const;
VectorNguyen& gan(const VectorNguyen& vectorX);
int* batDau();
int* ketThuc();
const int* batDau() const;
const int* ketThuc() const;
private:
int n;
int* conTro;
};
VectorNguyen::VectorNguyen() :n{ 0 }, conTro{ nullptr } {}
VectorNguyen::VectorNguyen(int soLuong) : n{ soLuong }, conTro{ new int[soLuong] } {}
VectorNguyen::VectorNguyen(int soLuong, int giaTri) : n{ soLuong }, conTro{ new int[soLuong] }
{
std::fill_n(conTro, n, giaTri);
}
VectorNguyen::VectorNguyen(const VectorNguyen& vectorX) : n{ vectorX.n }, conTro{ new int[n] }
{
std::copy_n(vectorX.conTro, vectorX.n, conTro);
}
VectorNguyen::~VectorNguyen()
{
delete[] conTro;
}
int VectorNguyen::kichThuoc() const
{
return n;
}
const int& VectorNguyen::tai(int chiSo) const
{
if (chiSo < 0 || chiSo >= n)
{
std::cerr << "Loi chi so: chi so ngoai pham vi
";
std::exit(1);
}
return conTro[chiSo];
}
int& VectorNguyen::tai(int chiSo)
{
return const_cast(static_cast<const VectorNguyen*>(this)->tai(chiSo));
}
VectorNguyen& VectorNguyen::gan(const VectorNguyen& vectorX)
{
if (this == &vectorX)
return *this;
int* conTroTam;
conTroTam = new int[vectorX.n];
std::copy_n(vectorX.conTro, vectorX.n, conTroTam);
delete[] conTro;
n = vectorX.n;
conTro = conTroTam;
return *this;
}
int* VectorNguyen::batDau()
{
return conTro;
}
int* VectorNguyen::ketThuc()
{
return conTro + n;
}
const int* VectorNguyen::batDau() const
{
return conTro;
}
const int* VectorNguyen::ketThuc() const
{
return conTro + n;
}
// thuNghiemVector.cpp
#include "VectorNguyen.hpp"
#include <iostream>
void thuNghiem1();
void thuNghiem2();
void hienThi1(const VectorNguyen& vectorX);
void hienThi2(const VectorNguyen& vectorX);
int main()
{
std::cout << "Thu nghiem 1:
";
thuNghiem1();
std::cout << "
Thu nghiem 2:
";
thuNghiem2();
}
void thuNghiem1()
{
int n;
std::cout << "Nhap n: ";
std::cin >> n;
VectorNguyen vectorA(n);
for (auto i = 0; i < n; ++i)
vectorA.tai(i) = (i + 1) * 10;
std::cout << "vectorA: "; hienThi1(vectorA);
VectorNguyen vectorB(n, 42);
VectorNguyen vectorC(vectorB);
vectorB.tai(0) = -1;
std::cout << "vectorB: "; hienThi1(vectorB);
std::cout << "vectorC: "; hienThi1(vectorC);
}
void thuNghiem2()
{
const VectorNguyen vectorX(5, 42);
VectorNguyen vectorY;
vectorY.gan(vectorX);
std::cout << "vectorX: "; hienThi2(vectorX);
std::cout << "vectorY: "; hienThi2(vectorY);
}
void hienThi1(const VectorNguyen& vectorX)
{
if (vectorX.kichThuoc() == 0)
{
std::cout << '
';
return;
}
std::cout << vectorX.tai(0);
for (auto i = 1; i < vectorX.kichThuoc(); ++i)
std::cout << ", " << vectorX.tai(i);
std::cout << '
';
}
void hienThi2(const VectorNguyen& vectorX) {
if (vectorX.kichThuoc() == 0)
{
std::cout << '
';
return;
}
auto it = vectorX.batDau();
std::cout << *it;
for (it = vectorX.batDau() + 1; it != vectorX.ketThuc(); ++it)
std::cout << ", " << *it;
std::cout << '
';
}
Câu hỏi và trả lời
Câu 1: Khi cố gắng gán chính nó cho chính nó, mã nguồn gốc sẽ kiểm tra một lần ở đầu, có thể tránh dữ liệu gốc bị giải phóng; trong phiên bản 2, việc giải phóng dữ liệu gốc trực tiếp sẽ dẫn đến dữ liệu bị giải phóng bất thường nếu gán cho chính nó, `conTro` trở thành con trỏ hoang dã. Nếu việc cấp phát bộ nhớ bằng `new[]` thất bại và báo lỗi, mã nguồn gốc sử dụng con trỏ tạm thời để trỏ đến bộ nhớ được cấp phát, nếu thất bại thì không ảnh hưởng đến dữ liệu gốc; phiên bản 2 giải phóng dữ liệu gốc và sau đó sử dụng chính con trỏ `ptr` của nó để trỏ đến bộ nhớ được cấp phát, nếu cấp phát thất bại, dữ liệu gốc không thể tìm lại, `ptr` là con trỏ hoang dã, độ an toàn thấp.
Câu 2:
- (1) Chức năng: Chuyển đổi con trỏ `this` không phải `const` thành `const VectorNguyen*`. Trước khi chuyển đổi: `VectorNguyen*`; Sau khi chuyển đổi: `const VectorNguyen*`. Mục đích: Gọi giao diện `at()` phiên bản `const`, tái sử dụng mã.
- (2) Chức năng: Loại bỏ thuộc tính `const`. Trước khi chuyển đổi: `const int&`; Sau khi chuyển đổi: `int&`. Mục đích: Trả về tham chiếu có thể sửa đổi trong phiên bản không phải `const`, đồng thời tái sử dụng logic của phiên bản `const`.
Câu 3: Bộ biên dịch sẽ ưu tiên chọn hàm phù hợp nhất. Khi kiểu `const VectorNguyen` hoặc gọi `begin()` thông qua con trỏ/ tham chiếu `const`, sẽ chọn phiên bản `const` của `begin()`; khi kiểu không phải `const` hoặc gọi `begin()` thông qua con trỏ/ tham chiếu không phải `const`, sẽ chọn phiên bản không phải `const` của `begin()`.
Câu 4: Có thể viết lại. `std::fill(conTro, n, giaTri)` có chức năng gán `n` phần tử bắt đầu từ `conTro` bằng `giaTri`; `std::copy_n` có chức năng sao chép `vi.n` phần tử bắt đầu từ `vi.conTro` vào vùng chứa bắt đầu từ `conTro`. Cập nhật đầu tiên là gán hàng loạt dữ liệu vào đối tượng `VectorNguyen`, cập nhật thứ hai là sao chép dữ liệu từ `vi` vào đối tượng mới, cập nhật thứ ba là gán hàng loạt dữ liệu từ bộ nhớ tạm thời vào đối tượng ban đầu.
Thí nghiệm 4: Xây dựng lớp `MaTran` tùy chỉnh
Bài tập này yêu cầu xây dựng một lớp ma trận để quản lý dữ liệu hai chiều.
// MaTran.hpp
#pragma once
#include <iostream>
#include <algorithm>
#include <cstdlib>
class MaTran {
public:
MaTran(int soHang_, int soCot_, double giaTri = 0); // Tao doi tuong ma tran rows_*cols_, gia tri khoi tao la value
MaTran(int soHang_, double giaTri = 0); // Tao doi tuong ma tran vuong rows_*rows_, gia tri khoi tao la value
MaTran(const MaTran& x); // Sao chep sau
~MaTran();
void dat(const double* giaTri, int kichThuoc); // Sao chep du lieu theo hang tu pvalue, yeu cau kichThuoc=rows*cols, neu khong thi thoat va bao loi
void xoa(); // Dat tat ca phan tu cua doi tuong ma tran ve 0
const double& tai(int i, int j) const; // Tra ve tham chieu const cua phan tu tai chi so (i,j) (bao loi va thoat neu vuot range)
double& tai(int i, int j); // Tra ve tham chieu cua phan tu tai chi so (i,j) (bao loi va thoat neu vuot range)
int soHang() const; // Tra ve so hang cua doi tuong ma tran
int soCot() const; // Tra ve so cot cua doi tuong ma tran
void in() const; // In du lieu theo hang
};
MaTran::MaTran(int soHang_, int soCot_, double giaTri) : soHang{ soHang_ }, soCot{ soCot_ }, conTro{ new double[soHang_ * soCot_] }
{
std::fill_n(conTro, soHang_ * soCot_, giaTri);
}
MaTran::MaTran(int soHang_, double giaTri) : soHang{ soHang_ }, soCot{ soHang_ }, conTro{ new double[soHang_ * soHang_] }
{
std::fill_n(conTro, soHang_ * soHang_, giaTri);
}
MaTran::MaTran(const MaTran& x) : soHang{ x.soHang }, soCot{ x.soCot }, conTro{ new double[x.soHang * x.soCot] }
{
std::copy_n(x.conTro, x.soHang * x.soCot, conTro);
}
MaTran::~MaTran()
{
delete[] conTro;
}
void MaTran::dat(const double* giaTri, int kichThuoc)
{
if (soHang * soCot != kichThuoc)
{
std::cerr << "Kich thuoc dat khong phu hop voi kich thuoc ma tran";
return;
}
for (int i = 0; i < kichThuoc; i++)
conTro[i] = giaTri[i];
}
void MaTran::xoa()
{
for (int i = 0; i < (soHang * soCot); i++)
conTro[i] = 0;
}
const double& MaTran::tai(int i, int j) const
{
if (i < 0 || j < 0 || i >= soHang || j >= soCot)
{
std::cerr << "Tai khong phu hop voi kich thuoc ma tran (const)";
;
}
return conTro[i * soCot + j];
}
double& MaTran::tai(int i, int j)
{
return const_cast(static_cast<const MaTran*>(this)->tai(i, j));
}
int MaTran::soHang() const
{
return soHang;
}
int MaTran::soCot() const
{
return soCot;
}
void MaTran::in() const
{
if (soHang == 0 || soCot == 0)
{
std::cout << '
';
return;
}
for (int i = 0; i < soHang; i++)
{
int j = 0;
std::cout << conTro[i * soCot];
for (j = 1; j < soCot; j++)
{
std::cout << ", " << conTro[i * soCot + j];
}
std::cout << '
';
}
}
// thuNghiemMaTran.cpp
#include <iostream>
#include <cstdlib>
#include "MaTran.hpp"
void thuNghiem1();
void thuNghiem2();
void hienThiHang(const MaTran& m, int chiSoHang);
int main() {
std::cout << "Thu nghiem 1:
";
thuNghiem1();
std::cout << "
Thu nghiem 2:
";
thuNghiem2();
}
void thuNghiem1() {
double danhSachGiaTri[1000] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int soHang, soCot;
std::cout << "Nhap so hang va so cot: ";
std::cin >> soHang >> soCot;
MaTran maTran1(soHang, soCot); // Tao doi tuong ma tran maTran1, kich thuoc soHang x soCot
maTran1.dat(danhSachGiaTri, soHang * soCot); // Gan gia tri tu mang 1 chieu danhSachGiaTri cho ma tran maTran1 theo hang
MaTran maTran2(soCot, soHang); // Tao doi tuong ma tran maTran2, kich thuoc soCot x soHang
maTran2.dat(danhSachGiaTri, soCot * soHang); // Gan gia tri tu mang 1 chieu danhSachGiaTri cho ma tran maTran2 theo hang
MaTran maTran3(soHang); // Tao doi tuong ma tran vuong soHang x soHang
maTran3.dat(danhSachGiaTri, soHang * soHang); // Gan gia tri tu mang 1 chieu danhSachGiaTri cho ma tran maTran3 theo hang
std::cout << "Doi tuong ma tran maTran1:
"; maTran1.in();
std::cout << "Doi tuong ma tran maTran2:
"; maTran2.in();
std::cout << "Doi tuong ma tran maTran3:
"; maTran3.in();
}
void thuNghiem2() {
MaTran maTran1(2, 3, -1);
const MaTran maTran2(maTran1);
std::cout << "Doi tuong ma tran maTran1:
"; maTran1.in();
std::cout << "Doi tuong ma tran maTran2:
"; maTran2.in();
maTran1.xoa();
maTran1.tai(0, 0) = 1;
std::cout << "maTran1 sau khi cap nhat:
";
std::cout << "Hang 0 cua doi tuong ma tran maTran1: "; hienThiHang(maTran1, 0);
std::cout << "Hang 0 cua doi tuong ma tran maTran2: "; hienThiHang(maTran2, 0);
}
// In tat ca phan tu cua hang chiSoHang trong doi tuong ma tran
void hienThiHang(const MaTran& m, int chiSoHang) {
if (chiSoHang < 0 || chiSoHang >= m.soHang()) {
std::cerr << "Loi chi so: chi so hang ngoai pham vi
";
exit(1);
}
std::cout << m.tai(chiSoHang, 0);
for (int j = 1; j < m.soCot(); ++j)
std::cout << ", " << m.tai(chiSoHang, j);
std::cout << '
';
}
Thí nghiệm 5: Xây dựng sổ địa chỉ
Bài tập này xây dựng một ứng dụng sổ địa chỉ đơn giản sử dụng các lớp kết hợp.
// LienHe.hpp
#pragma once
#include <iostream>
#include <string>
class LienHe {
public:
LienHe(const std::string& ten_, const std::string& soDienThoai_);
const std::string& layTen() const;
const std::string& laySoDienThoai() const;
void hienThi() const;
private:
std::string ten; // Bat buoc
std::string soDienThoai; // Bat buoc
};
LienHe::LienHe(const std::string& ten_, const std::string& soDienThoai_) :ten{ ten_ }, soDienThoai{ soDienThoai_ } {}
const std::string& LienHe::layTen() const {
return ten;
}
const std::string& LienHe::laySoDienThoai() const {
return soDienThoai;
}
void LienHe::hienThi() const {
std::cout << ten << ", " << soDienThoai;
}
// SoDienThoai.hpp
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "LienHe.hpp"
class SoDienThoai {
public:
void themLienHe(const std::string& ten, const std::string& soDienThoai); // Them lien he
void xoaLienHe(const std::string& ten); // Xoa lien he
void timKiemLienHe(const std::string& ten) const; // Tim kiem lien he
void hienThiTatCaLienHe() const; // Hien thi tat ca lien he
size_t soLuong() const;
private:
int timChiSo(const std::string& ten) const; // Tra ve chi so cua lien he trong danhSachLienHe, neu khong ton tai, tra ve -1
void sapXepTheoTen(); // Sap xep danh ba theo thu tu tu dien cua ten
private:
std::vector<LienHe> danhSachLienHe;
};
void SoDienThoai::themLienHe(const std::string& ten, const std::string& soDienThoai) {
if (timChiSo(ten) == -1) {
danhSachLienHe.push_back(LienHe(ten, soDienThoai));
std::cout << ten << " da them thanh cong.
";
sapXepTheoTen();
return;
}
std::cout << ten << " da ton tai. Them that bai!
";
}
void SoDienThoai::xoaLienHe(const std::string& ten) {
int i = timChiSo(ten);
if (i == -1) {
std::cout << ten << " khong tim thay, xoa that bai!
";
return;
}
danhSachLienHe.erase(danhSachLienHe.begin() + i);
std::cout << ten << " da xoa thanh cong.
";
}
void SoDienThoai::timKiemLienHe(const std::string& ten) const {
int i = timChiSo(ten);
if (i == -1) {
std::cout << ten << " khong tim thay!
";
return;
}
danhSachLienHe[i].hienThi();
std::cout << '
';
}
void SoDienThoai::hienThiTatCaLienHe() const {
for (auto& c : danhSachLienHe) {
c.hienThi();
std::cout << '
';
}
}
size_t SoDienThoai::soLuong() const {
return danhSachLienHe.size();
}
// Da hoan thien 1: int timChiSo(const std::string &ten) const; thuc hien
// Tra ve chi so cua lien he trong danhSachLienHe; neu khong ton tai, tra ve -1
int SoDienThoai::timChiSo(const std::string& ten) const
{
for (size_t i = 0; i < danhSachLienHe.size(); i++)
{
if (danhSachLienHe.at(i).layTen() == ten)
return i;
}
return -1;
}
// Da hoan thien 2: void SoDienThoai::sapXepTheoTen(); thuc hien
// Sap xep danh ba theo thu tu tu dien cua ten
void SoDienThoai::sapXepTheoTen()
{
int n = danhSachLienHe.size();
for (size_t i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (danhSachLienHe.at(j).layTen() > danhSachLienHe.at(j + 1).layTen())
std::swap(danhSachLienHe.at(j), danhSachLienHe.at(j + 1));
}
}
}
// thuNghiemSoDienThoai.cpp
#include "SoDienThoai.hpp"
void kiemTra() {
SoDienThoai danhBa;
std::cout << "1. Them lien he
";
danhBa.themLienHe("Bob", "18199357253");
danhBa.themLienHe("Alice", "17300886371");
danhBa.themLienHe("Linda", "18184538072");
danhBa.themLienHe("Alice", "17300886371");
std::cout << "
2. Hien thi lien he
";
std::cout << "Co " << danhBa.soLuong() << " lien he.
";
danhBa.hienThiTatCaLienHe();
std::cout << "
3. Tim kiem lien he
";
danhBa.timKiemLienHe("Bob");
danhBa.timKiemLienHe("David");
std::cout << "
4. Xoa lien he
";
danhBa.xoaLienHe("Bob");
danhBa.xoaLienHe("David");
}
int main() {
kiemTra();
}