实验三 类和对象_基础编程2

实验任务1

实验源代码如下:

button.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <string>
 5 
 6 class Button {
 7 public:
 8     Button(const std::string& label_);
 9     const std::string& get_label() const;
10     void click();
11 
12 private:
13     std::string label;
14 };
15 
16 Button::Button(const std::string& label_) : label{ label_ } {
17 }
18 
19 inline const std::string& Button::get_label() const {
20     return label;
21 }
22 
23 inline void Button::click() {
24     std::cout << "Button '" << label << "' clicked\n";
25 }

window.hpp

 1 #pragma once
 2 #include <iostream>
 3 #include <vector>
 4 #include <algorithm>
 5 #include "button.hpp"
 6 
 7 class Window {
 8 public:
 9     Window(const std::string& title_);
10     void display() const;
11     void close();
12     void add_button(const std::string& label);
13     void click_button(const std::string& label);
14 
15 private:
16     bool has_button(const std::string& label) const;
17 
18 private:
19     std::string title;
20     std::vector<Button> buttons;
21 };
22 
23 Window::Window(const std::string& title_) : title{ title_ } {
24     buttons.push_back(Button("close"));
25 }
26 
27 inline void Window::display() const {
28     std::string s(40, '*');
29     std::cout << s << std::endl;
30     std::cout << "window : " << title << std::endl;
31     int cnt = 0;
32     for (const auto& button : buttons)
33         std::cout << ++cnt << ". " << button.get_label() << std::endl;
34     std::cout << s << std::endl;
35 }
36 
37 inline void Window::close() {
38     std::cout << "close window '" << title << "'" << std::endl;
39     click_button("close");
40 }
41 
42 inline bool Window::has_button(const std::string& label) const {
43     for (const auto& button : buttons)
44         if (button.get_label() == label)
45             return true;
46 
47     return false;
48 }
49 
50 inline void Window::add_button(const std::string& label) {
51     if (has_button(label))
52         std::cout << "button " << label << " already exists!\n";
53     else
54         buttons.push_back(Button(label));
55 }
56 
57 inline void Window::click_button(const std::string& label) {
58     for (auto& button : buttons)
59         if (button.get_label() == label) {
60             button.click();
61             return;
62         }
63 
64     std::cout << "no button: " << label << std::endl;
65 }

task1.cpp

 1 #include "window.hpp"
 2 #include <iostream>
 3 
 4 void test() {
 5     Window w("Demo");
 6     w.add_button("add");
 7     w.add_button("remove");
 8     w.add_button("modify");
 9     w.add_button("add");
10     w.display();
11     w.close();
12 }
13 
14 int main() {
15     std::cout << "用组合类模拟简单GUI:\n";
16     test();
17 }

实验运行结果截图如下:

82fa9a49d4941306004746fe678db050

问题1:这个范例中,window和button是组合关系吗?

是组合关系,在window类中包含了button成员,在vector<button>中。

问题2: bool has_button(const std::string &label) const; 被设计为私有
(1).若将其改为公有,有何优点或风险?
优点:允许类外部调用该函数,使类的外部功能更多更完善
风险:打破了类的封装,泄露类内部按钮信息
(2)设计类时,如何判断一个成员函数应为 public 还是 private?
public:该函数不仅是内部的实现细节,用户需要该函数做功能实现,且函数公开不会泄露数据或破坏对象状态
private:该函数仅为辅助类内部实现其他功能的细节,用户不需要该函数做功能实现,且函数公开会泄露数据或破坏对象状态
 
问题3: Button 的接口 const std::string& get_label() const; 返回 const std::string& 。对比以下两种接口设计在性能和安全性方面的差异并精炼陈述。
接口1: const std::string& get_label() const;
接口2: const std::string get_label() const;
性能:接口1利用引用,不会调用复制构造函数,省去了复制开销,性能更好,接口2需要调用复制构造函数,性能略弱
安全性:两者均返回const值,外部不可修改,安全性有保障。
 
问题4:把代码中所有 xx.push_back(Button(xxx)) 改成 xx.emplace_back(xxx) ,观察程序是否正常运行;查阅资料,回答两种写法的差别。
可以正常运行。push_back和emplace_back功能都为向vector容器末尾添加元素,push_back首先会创建一个元素,然后将元素拷贝或移动到容器中,若拷贝则会删除先前创建的元素,emplace_back则是直接在容器尾部创建元素,省去了拷贝或移动元素的过程,提高了性能。
 
实验任务2
实验源代码如下:
 1 #include <iostream>
 2 #include <vector>
 3 
 4 void test1();
 5 void test2();
 6 void output1(const std::vector<int>& v);
 7 void output2(const std::vector<int>& v);
 8 void output3(const std::vector<std::vector<int>>& v);
 9 
10 int main() {
11     std::cout << "深复制验证1: 标准库vector<int>\n";
12     test1();
13 
14     std::cout << "\n深复制验证2: 标准库vector<int>嵌套使用\n";
15     test2();
16 }
17 
18 void test1() {
19     std::vector<int> v1(5, 42);
20     const std::vector<int> v2(v1);
21 
22     std::cout << "**********拷贝构造后**********\n";
23     std::cout << "v1: "; output1(v1);
24     std::cout << "v2: "; output1(v2);
25 
26     v1.at(0) = -1;
27 
28     std::cout << "**********修改v1[0]后**********\n";
29     std::cout << "v1: "; output1(v1);
30     std::cout << "v2: "; output1(v2);
31 }
32 
33 void test2() {
34     std::vector<std::vector<int>> v1{ {1, 2, 3}, {4, 5, 6, 7} };
35     const std::vector<std::vector<int>> v2(v1);
36 
37     std::cout << "**********拷贝构造后**********\n";
38     std::cout << "v1: "; output3(v1);
39     std::cout << "v2: "; output3(v2);
40 
41     v1.at(0).push_back(-1);
42 
43     std::cout << "**********修改v1[0]后**********\n";
44     std::cout << "v1: \n";  output3(v1);
45     std::cout << "v2: \n";  output3(v2);
46 }
47 
48 void output1(const std::vector<int>& v) {
49     if (v.size() == 0) {
50         std::cout << '\n';
51         return;
52     }
53 
54     std::cout << v.at(0);
55     for (auto i = 1; i < v.size(); ++i)
56         std::cout << ", " << v.at(i);
57     std::cout << '\n';
58 }
59 
60 void output2(const std::vector<int>& v) {
61     if (v.size() == 0) {
62         std::cout << '\n';
63         return;
64     }
65 
66     auto it = v.begin();
67     std::cout << *it;
68 
69     for (it = v.begin() + 1; it != v.end(); ++it)
70         std::cout << ", " << *it;
71     std::cout << '\n';
72 }
73 
74 void output3(const std::vector<std::vector<int>>& v) {
75     if (v.size() == 0) {
76         std::cout << '\n';
77         return;
78     }
79 
80     for (auto& i : v)
81         output2(i);
82 }

实验运行结果截图如下:

28cba148992f10ccdfd8076b35c321b7

问题1:测试模块1中这两行代码分别完成了什么构造? v1 、 v2 各包含多少个值为 42 的数据项?
37bf04016d571f000e891ca94c1c7657

第一行是普通构造函数,传入了两个参数,前者为元素数量,后者为元素值。第二行是复制构造函数,传入v1并构造一个和v1一样的v2。v1和v2都是包含5个值为42的数据项

问题2:测试模块2中这两行代码执行后, v1.size() 、 v2.size() 、 v1[0].size() 分别是多少?
64321df4af5ed8ede80211dd7db5cb17

添加代码std::cout << v1.size() << ", " << v2.size() << ", " << v1[0].size() << std::endl;运行结果截图如下:

e260b2c02075a5163e7da1277c1d82a5

三者值分别为2,2,3

 

问题3:测试模块1中,把 v1.at(0) = -1; 写成 v1[0] = -1; 能否实现同等效果?两种用法有何区别?
可以实现同等效果,[]用法不会进行边界检查,越界访问会返回错误的引用,而at()会进行边界检查,越界时会抛出异常。
 
问题4:测试模块2中执行 v1.at(0).push_back(-1); 后
(1) 用以下两行代码,能否输出-1?为什么?
8c790bf9fb1b317c4708c4bfa55e24e1

可以输出-1,利用r取得了嵌套vector的vector中的第一个vector,并取其最后一个元素,而-1正好添加在了此vector中的最后一个元素,故可以输出-1

(2)r定义成用 const & 类型接收返回值,在内存使用上有何优势?有何限制?
优势:用引用形式接收返回值,省去了vector的复制构造环节,节省内存
限制:返回值为const形式,不可以对其进行修改操作
 
问题5:观察程序运行结果,反向分析、推断:
(1) 标准库模板类 vector 的复制构造函数实现的是深复制还是浅复制?
是深复制,若是浅复制,修改v1时v2也会随之修改,然而修改v1后v2不变,故是深复制
(2) vector<T>::at() 接口思考: 当 v 是 vector<int> 时, v.at(0) 返回值类型是什么?当 v 是 const vector<int> 时, v.at(0) 返回值类型又是什么?据此推断 at() 是否必须提供带 const 修饰的重载版本?
前者返回值类型是int&,后者返回值类型是const int&。
必须提供带const修饰的重载版本,若定义的对象为const类型,那么这个对象只能调用const类型的成员函数,若为非const类型的成员函数,调用时则会出错。
 
实验任务3
实验源代码如下:
vectorInt.hpp
  1 #pragma once
  2 
  3 #include <iostream>
  4 
  5
  6 class vectorInt{
  7 public:
  8     vectorInt();
  9     vectorInt(int n_);
 10     vectorInt(int n_, int value);
 11     vectorInt(const vectorInt &vi);
 12     ~vectorInt();
 13     
 14     int size() const;
 15     int& at(int index);
 16     const int& at(int index) const;
 17     vectorInt& assign(const vectorInt &vi);
 18 
 19     int* begin();
 20     int* end();
 21     const int* begin() const;
 22     const int* end() const;
 23 
 24 private:
 25     int n;     
 26     int *ptr;  
 27 };
 28 
 29 vectorInt::vectorInt():n{0}, ptr{nullptr} {
 30 }
 31 
 32 vectorInt::vectorInt(int n_): n{n_}, ptr{new int[n]} {
 33 }
 34 
 35 vectorInt::vectorInt(int n_, int value): n{n_}, ptr{new int[n_]} {
 36     for(auto i = 0; i < n; ++i)
 37         ptr[i] = value;
 38 }
 39 
 40 vectorInt::vectorInt(const vectorInt &vi): n{vi.n}, ptr{new int[n]} {
 41     for(auto i = 0; i < n; ++i)
 42         ptr[i] = vi.ptr[i];
 43 }
 44 
 45 vectorInt::~vectorInt() {
 46     delete [] ptr;
 47 }
 48 
 49 int vectorInt::size() const {
 50     return n;
 51 }
 52 
 53 const int& vectorInt::at(int index) const {
 54     if(index < 0 || index >= n) {
 55         std::cerr << "IndexError: index out of range\n";
 56         std::exit(1);
 57     }
 58 
 59     return ptr[index];
 60 }
 61 
 62 int& vectorInt::at(int index) {
 63     if(index < 0 || index >= n) {
 64         std::cerr << "IndexError: index out of range\n";
 65         std::exit(1);
 66     }
 67 
 68     return ptr[index];
 69 }
 70 
 71 vectorInt& vectorInt::assign(const vectorInt &vi) { 
 72     if(this == &vi) 
 73         return *this;
 74 
 75     int *ptr_tmp;
 76     ptr_tmp = new int[vi.n];
 77     for(int i = 0; i < vi.n; ++i)
 78         ptr_tmp[i] = vi.ptr[i];
 79     
 80     delete[] ptr;
 81     n = vi.n;
 82     ptr = ptr_tmp;
 83     return *this;
 84 }
 85 
 86 int* vectorInt::begin() {
 87     return ptr;
 88 }
 89 
 90 int* vectorInt::end() {
 91     return ptr+n;
 92 }
 93 
 94 const int* vectorInt::begin() const {
 95     return ptr;
 96 }
 97 
 98 const int* vectorInt::end() const {
 99     return ptr+n;
100 }

task3.cpp

 1 #include "vectorInt.hpp"
 2 #include <iostream>
 3 
 4 void test1();
 5 void test2();
 6 void output1(const vectorInt &vi);
 7 void output2(const vectorInt &vi);
 8 
 9 int main() {
10     std::cout << "测试1: \n";
11     test1();
12 
13     std::cout << "\n测试2: \n";
14     test2();
15 }
16 
17 void test1() {
18     int n;
19     std::cout << "Enter n: ";
20     std::cin >> n;
21 
22     vectorInt x1(n);
23     for(auto i = 0; i < n; ++i)
24         x1.at(i) = (i+1)*10;
25     std::cout << "x1: ";  output1(x1);
26 
27     vectorInt x2(n, 42);
28     vectorInt x3(x2);
29     x2.at(0) = -1;
30     std::cout << "x2: ";  output1(x2);
31     std::cout << "x3: ";  output1(x3);
32 }
33 
34 void test2() {
35     const vectorInt  x(5, 42);
36     vectorInt y;
37 
38     y.assign(x);
39 
40     std::cout << "x: ";  output2(x);
41     std::cout << "y: ";  output2(y);
42 }
43 
44 void output1(const vectorInt &vi) {
45     if(vi.size() == 0) {
46         std::cout << '\n';
47         return;
48     }
49         
50     std::cout << vi.at(0);
51     for(auto i = 1; i < vi.size(); ++i)
52         std::cout << ", " << vi.at(i);
53     std::cout << '\n';
54 }
55 
56 void output2(const vectorInt &vi) {
57     if(vi.size() == 0) {
58         std::cout << '\n';
59         return;
60     }
61     
62     auto it = vi.begin();
63     std::cout << *it;
64 
65     for(it = vi.begin()+1; it != vi.end(); ++it)
66         std::cout << ", " << *it;
67     std::cout << '\n';
68 }

实验运行结果截图如图所示:

9166624c11021f764327b4fbfb51fa5c

问题1:当前验证性代码中, vectorInt 接口 assign 实现是安全版本。如果把 assign 实现改成版本2,逐条指出版本 2存在的安全隐患和缺陷。
70696382acef186d41fbe8a7efedd66c

1.原代码一开始会进行判等操作,只要调用assign的对象和传入的vi是同一个对象,下面就省去了复制操作的开销,而版本2此代码没有考虑到这点

2.版本2代码一开始就将ptr内存回收,若调用assign的对象和传入的vi是同一个对象,回收ptr后vi.ptr也被释放,后续运行会出错

3.原代码使用ptr_tmp,首先将vi信息复制给ptr_tmp,无错误后再将ptr_tmp换为ptr,保证了数据的正确性,避免获得错误数据

 

问题2:当前验证性代码中,重载接口 at 内部代码完全相同。若把非 const 版本改成如下实现,可消除重复并遵循“最小化接口”原则
da6139d9bdfebe75d7a8170f7fabcd5c
查阅资料,回答:
(1) static_cast<const vectorInt*>(this) 的作用是什么?转换前后 this 的类型分别是什么?转换目的?
static_cast<const vectorInt*>(this) 将this指针转化为const vectorInt*类型,this指针转换前是vectorInt,转换后是const vectorInt*,转换目的为这样可以调用const类型的at()函数
(2) const_cast<int&> 的作用是什么?转换前后的返回类型分别是什么?转换目的?
const_cast<int&> 将返回值类型转化为int&类型,返回值转换前为const int&类型,转换后为int&类型,转换目的为与函数返回值类型相匹配
 
问题3: vectorInt 类封装了 begin() 和 end() 的const/非const接口。
(1)以下代码片段,分析编译器如何选择重载版本,并总结这两种重载分别适配什么使用场景。
92335c387093f3adfb1e94811e87f7ae

it1调用非const类型的begin()函数,it2调用const类型的begin()函数

非const类型的begin()函数适用于容器内部元素均为非const类型的容器,而const类型的适用于容器内部元素均为const类型的容器

(2)标准库迭代器本质上是指针的封装。 vectorInt 直接返回原始指针作为迭代器,这种设计让你对迭代器有什么新的理解?

迭代器的本质就是指针,通过指针去完成容器内部元素的遍历、访问等操作

 

问题4:以下两个构造函数及 assign 接口实现,都包含内存块的赋值和复制操作。使用算法库 <algorithm> 改成如下写法是否可以?回答这3行更新代码的功能
46f9936f6d72da4fc79630bd43446357

换成这三种写法可以

第一行:以ptr指向位置为起点,将此后的n个元素赋值为value

第二行:将以vi.ptr为起点的vi.n个元素复制到以ptr为起点的位置

第三行:将以vi.ptr为起点的vi.n个元素复制到以ptr_tmp为起点的位置

 

实验任务4

程序源代码如下:

matrix.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cstdlib>
 6 
 7 class Matrix {
 8 public:
 9     Matrix(int rows_, int cols_, double value = 0); 
10     Matrix(int rows_, double value = 0);    
11     Matrix(const Matrix& x);    
12     ~Matrix();
13 
14     void set(const double* pvalue, int size);
15     void clear();
16 
17     const double& at(int i, int j) const;   
18     double& at(int i, int j);   
19 
20     int rows() const;  
21     int cols() const;   
22 
23     void print() const;   
24 
25 private:
26     int n_rows;     
27     int n_cols;       
28     double* ptr;    
29 };
30 
31 Matrix::Matrix(int rows_, int cols_, double value) :n_rows(rows_), n_cols(cols_), ptr(new double[rows_* cols_]) {
32     for (int i = 0; i < n_rows*n_cols; i++) {
33         ptr[i] = value;
34     }
35 }
36 
37 Matrix::Matrix(int rows_, double value) :n_rows(rows_), n_cols(rows_), ptr(new double[rows_* rows_]) {
38     for (int i = 0; i < n_rows * n_cols; i++) {
39         ptr[i] = value;
40     }
41 }
42 
43 Matrix::Matrix(const Matrix& x):n_rows(x.n_rows), n_cols(x.n_cols), ptr(new double[x.n_rows * x.n_cols]){
44     for (int i = 0; i < n_rows * n_cols; i++) {
45         ptr[i] = x.ptr[i];
46     }
47 }
48 
49 Matrix::~Matrix() { delete[]ptr; }
50 
51 void Matrix::set(const double* pvalue, int size) {
52     if (size != n_rows * n_cols) {
53         std::cout << "size ERROR" << std::endl;
54         return;
55     }
56     else {
57         for (int i = 0; i < size; i++) {
58             ptr[i] = pvalue[i];
59         }
60     }
61 }
62 
63 void Matrix::clear() {
64     for (int i = 0; i < n_rows * n_cols; i++) {
65         ptr[i] = 0;
66     }
67 }
68 
69 const double& Matrix::at(int i, int j) const {
70     if (i < 0 || j < 0 || i >= n_rows || j >= n_cols) {
71         std::cout << "at ERROR" << std::endl;
72     }
73     else { return ptr[i * n_cols + j]; }
74 }
75 
76 double& Matrix::at(int i, int j) { return const_cast<double&>(static_cast<const Matrix*>(this)->at(i, j)); }
77 
78 int Matrix::rows() const { return n_rows; }
79 
80 int Matrix::cols() const { return n_cols; }
81 
82 void Matrix::print() const {
83     for (int i = 0; i < n_rows; ++i) {
84         for (int j = 0; j < n_cols; ++j) {
85             std::cout << ptr[i * n_cols + j];
86             if(j!=n_cols-1)std::cout << ", ";
87         }
88         std::cout << std::endl;
89     }
90 }

task4.cpp

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include "matrix.hpp"
 4 
 5 void test1();
 6 void test2();
 7 void output(const Matrix& m, int row_index);
 8 
 9 int main() {
10     std::cout << "测试1: \n";
11     test1();
12 
13     std::cout << "\n测试2: \n";
14     test2();
15 }
16 
17 void test1() {
18     double x[1000] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
19 
20     int n, m;
21     std::cout << "Enter n and m: ";
22     std::cin >> n >> m;
23 
24     Matrix m1(n, m);    
25     m1.set(x, n * m);     
26 
27     Matrix m2(m, n);    
28     m2.set(x, m * n);     
29 
30     Matrix m3(n);      
31     m3.set(x, n * n);     
32 
33     std::cout << "矩阵对象m1: \n";   m1.print();
34     std::cout << "矩阵对象m2: \n";   m2.print();
35     std::cout << "矩阵对象m3: \n";   m3.print();
36 }
37 
38 void test2() {
39     Matrix m1(2, 3, -1);
40     const Matrix m2(m1);
41 
42     std::cout << "矩阵对象m1: \n";   m1.print();
43     std::cout << "矩阵对象m2: \n";   m2.print();
44 
45     m1.clear();
46     m1.at(0, 0) = 1;
47 
48     std::cout << "m1更新后: \n";
49     std::cout << "矩阵对象m1第0行 "; output(m1, 0);
50     std::cout << "矩阵对象m2第0行: "; output(m2, 0);
51 }
52 
53 void output(const Matrix& m, int row_index) {
54     if (row_index < 0 || row_index >= m.rows()) {
55         std::cerr << "IndexError: row index out of range\n";
56         exit(1);
57     }
58 
59     std::cout << m.at(row_index, 0);
60     for (int j = 1; j < m.cols(); ++j)
61         std::cout << ", " << m.at(row_index, j);
62     std::cout << '\n';
63 }

程序运行结果截图如下:

7fdb52a7e6c57051913459cc73de01ef

 

实验任务5

实验源代码如下:

contact.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <string>
 5 
 6 class Contact {
 7 public:
 8     Contact(const std::string& name_, const std::string& phone_);
 9 
10     const std::string& get_name() const;
11     const std::string& get_phone() const;
12     void display() const;
13 
14 private:
15     std::string name;    
16     std::string phone;   
17 };
18 
19 Contact::Contact(const std::string& name_, const std::string& phone_) :name{ name_ }, phone{ phone_ } {
20 }
21 
22 const std::string& Contact::get_name() const {
23     return name;
24 }
25 
26 const std::string& Contact::get_phone() const {
27     return phone;
28 }
29 
30 void Contact::display() const {
31     std::cout << name << ", " << phone;
32 }

contactBook.hpp

 1 # pragma  once
 2 
 3 #include <iostream>
 4 #include <string>
 5 #include <vector>
 6 #include <algorithm>
 7 #include "contact.hpp"
 8 
 9 class ContactBook {
10 public:
11     void add(const std::string& name, const std::string& phone); 
12     void remove(const std::string& name);
13     void find(const std::string& name) const; 
14     void display() const; 
15     size_t size() const;
16 
17 private:
18     int index(const std::string& name) const;  
19     void sort(); 
20 
21 private:
22     std::vector<Contact> contacts;
23 };
24 
25 void ContactBook::add(const std::string& name, const std::string& phone) {
26     if (index(name) == -1) {
27         contacts.push_back(Contact(name, phone));
28         std::cout << name << " add successfully.\n";
29         sort();
30         return;
31     }
32 
33     std::cout << name << " already exists. fail to add!\n";
34 }
35 
36 void ContactBook::remove(const std::string& name) {
37     int i = index(name);
38 
39     if (i == -1) {
40         std::cout << name << " not found, fail to remove!\n";
41         return;
42     }
43 
44     contacts.erase(contacts.begin() + i);
45     std::cout << name << " remove successfully.\n";
46 }
47 
48 void ContactBook::find(const std::string& name) const {
49     int i = index(name);
50 
51     if (i == -1) {
52         std::cout << name << " not found!\n";
53         return;
54     }
55 
56     contacts[i].display();
57     std::cout << '\n';
58 }
59 
60 void ContactBook::display() const {
61     for (auto& c : contacts) {
62         c.display();
63         std::cout << '\n';
64     }
65 }
66 
67 size_t ContactBook::size() const {
68     return contacts.size();
69 }
70 
71 int ContactBook::index(const std::string& name) const{
72     int count = 0;
73     for (auto& i : contacts) {
74         if (i.get_name()==name) {
75             return count;
76         }
77         count++;
78     }
79     return -1;
80 }
81 
82 bool compare(Contact& a, Contact& b) {
83     return a.get_name() < b.get_name();
84 }
85 
86 void ContactBook::sort() {
87     std::sort(contacts.begin(), contacts.end(), compare);
88 }

task5.cpp

 1 #include "contactBook.hpp"
 2 
 3 void test() {
 4     ContactBook contactbook;
 5 
 6     std::cout << "1. add contacts\n";
 7     contactbook.add("Bob", "18199357253");
 8     contactbook.add("Alice", "17300886371");
 9     contactbook.add("Linda", "18184538072");
10     contactbook.add("Alice", "17300886371");
11 
12     std::cout << "\n2. display contacts\n";
13     std::cout << "There are " << contactbook.size() << " contacts.\n";
14     contactbook.display();
15 
16     std::cout << "\n3. find contacts\n";
17     contactbook.find("Bob");
18     contactbook.find("David");
19 
20     std::cout << "\n4. remove contact\n";
21     contactbook.remove("Bob");
22     contactbook.remove("David");
23 }
24 
25 int main() {
26     test();
27 }

实验结果截图如下:

aae6ced0f0d3798ed70bab644d2a590d

 

实验总结

通过此次实验,我最大的收获是最小化接口的应用,通过对数据类型的转换,可以将两功能相近但返回值类型不同的函数通过此方式相互调用可以使接口最小化,避免冗余代码的书写

posted @ 2025-11-19 21:30  摇摇车nuist  阅读(23)  评论(1)    收藏  举报