实验3

一、实验任务1

 源代码button.hpp

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

源代码window.hpp

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

源代码task1.cpp

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

运行结果展示:

image

 ps:在给出的示例代码中window出现了w大小写不统一的情况,需要稍加修改成统一形式。

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

答:是组合关系。类的的组合是has-a的关系,指的是一个类中的成员数据包含另一个类的对象,也就是这里在window类中包含有std::vector<Button> buttons(Button类的对象)。

 

问题2:bool has_button(const std::string &label) const; 被设计为私有。思考并回答:

(1)若将其改为公有接口,有何优点或风险?

答:这个函数是用来判断某个按键是否存在。如果改成公有接口的话,则在类的外部也可以直接进行调用来判断按键的存在性,但同时将私有转公有接口也会暴露类的内部,一定程度上有破坏类的封装性的风险,如果外部对直接调用的需要不强烈,我觉得还是私有接口更好一些,比较安全。

(2)设计类时,如何判断一个成员函数应为public还是private?(可从“用户是否需要”、“是否仅为内部实现 细节”、“是否易破坏对象状态”等角度分析。) 

答:在设计一个类时:1、如果用户需要的话,成员函数应为public类型供用户直接调用,反之定为private类型,减少对封装性的破坏。2.如果仅为内部实现细节,定为private类型就可以了,在类的内部直接完成对该函数的调用。3.如果易破坏对象状态,定为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返回值是普通的字符串类型副本。从性能上看,使用引用类型可以节省内存,返回的就是对象本身,不用拷贝一份对象的副本了,效率会更高一些。从安全性上看,一个函数不能返回局部对象的引用,当返回的是局部对象的引用(也就是在函数内部定义的对象)时,每次函数调用完都会释放一次局部对象的内存,这种情况下返回引用的地址里就没有内容了,无效返回,安全性差,所以接口2返回副本的安全性更好一些。

 

问题4:把代码中所有 xx.push_back(Button(xxx)) 改成 xx.emplace_back(xxx) ,观察程序是否正常运 行;查阅资料,回答两种写法的差别。 

答:可以正常运行。push_back函数和emplace_back函数都可以在vector容器的末尾添加数据,但push_back函数会先构造一个临时对象,然后再将其复制到容器中,而emplace_back函数会直接在容器末尾调用构造函数,避免临时对象的创建及拷贝。

(我查的资料来源:CSDN【cpp中容器push_back和emplace_back的区别 - CSDN App】https://blog.csdn.net/qq_44940689/article/details/142970810?sharetype=blog&shareId=142970810&sharerefer=APP&sharesource=2402_88154239&sharefrom=link)

 

二、实验任务2

源代码task2.cpp

 1 #include<iostream>
 2 #include<vector>
 3 void test1();
 4 void test2();
 5 void output1(const std::vector<int> &v);
 6 void output2(const std::vector<int> &v);
 7 void output3(const std::vector<std::vector<int>> &v);
 8 int main(){
 9     std::cout<<"深复制验证1:标准库vector<int>\n";
10     test1();
11     std::cout<<"\n深复制验证2:标准库vector<int>嵌套使用\n";
12     test2();
13 } 
14 void test1(){
15     std::vector<int> v1(5,42);
16     const std::vector<int> v2(v1);
17     std::cout<<"**********拷贝构造后**********\n";
18     std::cout<<"v1:";output1(v1);
19     std::cout<<"v2:";output1(v2);
20     v1.at(0)=-1;
21     std::cout<<"**********修改v1[0]后**********\n";
22     std::cout<<"v1:";output1(v1);
23     std::cout<<"v2:";output1(v2);
24 }
25 void test2(){
26     std::vector<std::vector<int>> v1{{1,2,3},{4,5,6,7}};
27     const std::vector<std::vector<int>> v2(v1);
28     std::cout<<"**********拷贝构造后**********\n";
29     std::cout<<"v1:\n";output3(v1);
30     std::cout<<"v2:\n";output3(v2);    
31     v1.at(0).push_back(-1);
32     std::cout<<"**********修改v1[0]后**********\n";
33     std::cout<<"v1:\n";output3(v1);
34     std::cout<<"v2:\n";output3(v2);
35 }
36 void output1(const std::vector<int> &v){
37     if(v.size()==0){
38         std::cout<<'\n';
39         return;
40     }
41     std::cout<<v.at(0);
42     for(auto i=1;i<v.size();++i)
43         std::cout<<","<<v.at(i);
44     std::cout<<'\n';
45 }
46 void output2(const std::vector<int> &v){
47     if(v.size()==0){
48         std::cout<<'\n';
49         return;        
50     }
51     auto it=v.begin();
52     std::cout<<*it;
53     for(it=v.begin()+1;it!=v.end();++it)
54         std::cout<<","<<*it;
55     std::cout<<'\n';
56 }
57 void output3(const std::vector<std::vector<int>> &v){
58     if(v.size()==0){
59         std::cout<<'\n';
60         return;        
61     }
62     for(auto &i:v)
63         output2(i);    
64 }
task2.cpp

运行结果展示:

image

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

image

 答:第一行代码定义了一个元素为int类型的vector容器v1,里面有5个元素,每个元素的值都为42。第二行代码定义了一个const类型的元素为int类型的vector容器v2,并且使用复制构造函数,将v1中的元素复制到v2中。v1和v2都包含5个值为42的元素。

 

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

image

 答:v1.size()是2,v2.size()是2,v1[0].size() 是3。

 

问题3:测试模块1中,把 v1.at(0) = -1; 写成 v1[0] = -1; 能否实现同等效果?两种用法有何区别? 

答:效果等同。at( )和[ ]都可以用来访问容器中的元素,但at( )可以检查在访问容器时是否越界,更安全一些。

 

问题4:测试模块2中执行v1.at(0).push_back(-1); 后 

(1)用以下两行代码,能否输出-1?为什么?

image

 答:可以输出-1。因为r是v1.at(0)的引用类型,容器内现在有1,2,3,-1,且r.size()-1=3,所以可以输出容器内最后一个元素-1。

image

 

(2)r定义成用const&类型接收返回值,在内存使用上有何优势?有何限制? 

答:在内存使用上可以节省内存避免拷贝,不需要分配新内存来复制vector容器中的所有元素。由于是const&类型,常量引用,所以不能对被绑定的对象进行修改。

 

问题5:观察程序运行结果,反向分析、推断:

(1)标准库模板类vector的复制构造函数实现的是深复制还是浅复制?

答:深复制,v2没有被改变。

(2)vector<T>::at()接口思考:当v是vector<int>时,v.at(0)返回值类型是什么?当v是const vector<int>时,v.at(0)返回值类型又是什么?据此推断at()是否必须提供带const修饰的重载版本? 

答:当v是vector<int>时,v.at(0)返回值类型是int&;当v是const vector<int>时,v.at(0)返回值类型是const int&。at()必须提供带const修饰的重载版本,因为const对象和非const对象都可以调用const类型,这样在不同情况下此接口都能够被使用。

 

三、实验任务3

源代码vectorInt.hpp

 1 #pragma once
 2 #include<iostream>
 3 class vectorInt{
 4 public:
 5     vectorInt();
 6     vectorInt(int n_);
 7     vectorInt(int n_,int value);
 8     vectorInt(const vectorInt &vi);
 9     ~vectorInt();
10     int size() const;
11     int& at(int index);
12     const int& at(int index) const;
13     vectorInt& assign(const vectorInt &vi);
14     int* begin();
15     int* end();
16     const int* begin() const;
17     const int* end() const;
18 private:
19     int n;
20     int *ptr;
21 };
22 vectorInt::vectorInt():n{0},ptr{nullptr}{}
23 vectorInt::vectorInt(int n_):n{n_},ptr{new int[n_]}{}
24 vectorInt::vectorInt(int n_,int value):n{n_},ptr{new int[n_]}{
25     for(auto i=0;i<n;i++)
26         ptr[i]=value;
27 }
28 vectorInt::vectorInt(const vectorInt &vi):n{vi.n},ptr{new int[n]}{
29     for(auto i=0;i<n;i++)
30         ptr[i]=vi.ptr[i];
31 }
32 vectorInt::~vectorInt(){
33     delete[]ptr;
34 }
35 int vectorInt::size() const{
36     return n;
37 }
38 const int& vectorInt::at(int index) const{
39     if(index<0||index>=n){
40         std::cerr<<"IndexError: index out of range\n";
41         std::exit(1);
42     }
43     return ptr[index];
44 }
45 int& vectorInt::at(int index){
46     if(index<0||index>=n){
47         std::cerr<<"IndexError: index out of range\n";
48         std::exit(1);
49     }
50     return ptr[index];
51 }
52 vectorInt& vectorInt::assign(const vectorInt &vi){
53     if(this==&vi)
54         return *this;
55     int *ptr_tmp;
56     ptr_tmp=new int[vi.n];
57     for(int i=0;i<vi.n;i++)
58         ptr_tmp[i]=vi.ptr[i];
59     delete[]ptr;
60     n=vi.n;
61     ptr=ptr_tmp;
62     return *this;
63 } 
64 int* vectorInt::begin(){
65     return ptr;
66 }
67 int* vectorInt::end(){
68     return ptr+n;
69 }
70 const int* vectorInt::begin() const{
71     return ptr;
72 }
73 const int* vectorInt::end() const{
74     return ptr+n;
75 }
vectorInt.hpp

源代码task3.cpp

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

运行结果展示:

image

 问题1:当前验证性代码中,vectorInt接口assign实现是安全版本。如果把assign实现改成版本2,逐条指出版本2存在的安全隐患和缺陷。(提示:对比两个版本,找出差异化代码,加以分析)

image

 答:1、版本2没有if(this==&vi)来判断是否为自赋值的操作,自赋值没有意义而且浪费内存。

2、版本2把delete[]ptr放在第一行,当没有自赋值操作时,遇到自赋值情况首先delete[]ptr会把自身释放掉,使vi.ptr[i]成为空值,后续无法对其进行访问。

 3.在版本1中分配内存ptr_tmp=new int[vi.n]用的是vi.n,在版本2中分配内存用的是ptr=new int[n]。如果像版本2一样先为n赋值,当面临new还没有成功分配内存时,在后续遍历访问0到n时可能出现越界访问。

 

问题2:当前验证性代码中,重载接口at内部代码完全相同。若把非const版本改成如下实现,可消除重复并遵循“最小化接口”原则(未来如需更新接口,只更新const接口,另一个会同步)。

image

 查阅资料,回答:

(1)static_cast<const vectorInt*>(this)的作用是什么?转换前后this的类型分别是什么?转换目的?

答:static_cast<const vectorInt*>(this)进行类型转换;把this指针从vectorInt*类型转换成const vectorInt*类型 (也就是从非const类型到const类型);可以增加安全性,仅一个接口就可以满足const对象和非const对象的使用,不需要再写重复率很高的两个重载接口。

(2)const_cast<int&>的作用是什么?转换前后的返回类型分别是什么?转换目的?

答: const_cast<int&>用来移除对象的const限定;从const int&类型转换到int&类型;因为这个at成员函数的返回类型是int&类型,所以在函数内return时的值也要是int&类型。而直接经过static_cast<const vectorInt*>(this)类型转换得到的是const类型,所以需要再次改const为非const满足函数要求。

 

问题3:vectorInt类封装了begin()和end()的const/非const接口。

(1)以下代码片段,分析编译器如何选择重载版本,并总结这两种重载分别适配什么使用场景。

image

 答:v1是非const类型对象,编译器会选择非const接口(没有的话也可以调用const);v2是const类型对象,编译器会选择const接口(不可以调用非const)。总结:const重载版本可以被const或非const对象调用,但此时不能修改其中的元素。非const重载版本只能被非const对象调用,但此时可以修改元素的值。

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

答:迭代器能够用来遍历容器的对象,在标准库里begin和end就是两个迭代器一个指向第一个元素,另一个指向最后一个元素,这两个迭代器的作用也就是像指针一样可以定位到收尾元素,但它们写起来会更加简洁一些,不需要写指针的符号。

 

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

image

 答:可以。第一行代码的功能是让ptr指向的对象被n个值为value的元素所填充;第二行代码的功能是把vi对象中从vi.ptr开始的vi.n个元素都复制到ptr所指向的对象中;第三行代码的功能与第二行类似,把vi对象中从vi.ptr开始的vi.n个元素都复制到ptr_tmp所指向的对象中。

 

四、实验任务4

源代码matrix.hpp

 1 #pragma once
 2 class Matrix{
 3 public:
 4     Matrix(int rows_,int cols_,double value=0);
 5     Matrix(int rows_,double value=0);
 6     Matrix(const Matrix &x);
 7     ~Matrix();
 8     void set(const double *pvalue,int size);
 9     void clear();
10     const double& at(int i,int j)const;
11     double& at(int i,int j);
12     int rows() const;
13     int cols() const;
14     void print() const;
15 private:
16     int n_rows;
17     int n_cols;
18     double *ptr;
19 };
matrix.hpp

源代码matrix.cpp

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include"matrix.hpp"
 4 Matrix::Matrix(int rows_,int cols_,double value):n_rows{rows_},n_cols{cols_},ptr{new double[n_rows*n_cols]}{
 5     for(auto i=0;i<n_rows*n_cols;i++)
 6         ptr[i]=value;
 7 }
 8 Matrix::Matrix(int rows_,double value):n_rows{rows_},n_cols{rows_},ptr{new double[n_rows*n_rows]}{
 9     for(auto i=0;i<n_rows*n_rows;i++)
10         ptr[i]=value;
11 }
12 Matrix::Matrix(const Matrix &x){
13     n_rows=x.rows();
14     n_cols=x.cols();
15     ptr=new double[n_rows*n_cols];
16     for(auto i=0;i<n_rows*n_cols;i++)
17         ptr[i]=x.ptr[i];
18 }
19 Matrix::~Matrix(){
20     delete[]ptr;
21 }
22 void Matrix::set(const double *pvalue,int size){
23     if(size!=n_rows*n_cols){
24         std::cerr<<"sizeError\n";
25         std::exit(1);
26     }
27     for(auto i=0;i<size;i++)
28         ptr[i]=pvalue[i];
29 }
30 void Matrix::clear(){
31     for(auto i=0;i<n_rows*n_cols;i++)
32         ptr[i]=0;
33 }
34 const double& Matrix::at(int i,int j)const{
35     if(i<0||i>=n_rows||j<0||j>=n_cols){
36         std::cerr<<"'i'or'j'Error\n";
37         std::exit(1);
38     }
39     return ptr[i*n_cols+j];
40 }
41 double& Matrix::at(int i,int j){
42     return const_cast<double&>(static_cast<const Matrix*>(this)->at(i,j));
43 }
44 int Matrix::rows() const{
45     return n_rows;
46 }
47 int Matrix::cols() const{
48     return n_cols;
49 }
50 void Matrix::print() const{
51     for(auto i=0;i<n_rows;i++){
52         for(auto j=0;j<n_cols-1;j++)
53             std::cout<<Matrix::at(i,j)<<",";
54         std::cout<<Matrix::at(i,n_cols-1)<<"\n";
55     }
56 }
matrix.cpp

源代码task4.cpp

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

运行成果展示:

image

 

五、实验任务5

源代码contact.hpp

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

源代码contactBook.hpp

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

源代码task5.cpp

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

 运行成果展示:

image

 

实验总结:1.在类的成员函数声明时如果已经为某个变量赋了初值,在定义时就不需要再写一次。在完成实验4时我的函数声明和定义都写了value=0,不仔细看找不到报错点。

2.类的成员函数不能直接用做std::sort的比较函数,在实验5中,我先定义comparename是成员函数,但这种情况下需要对象来调用,不如使用自由函数简洁。

3.size_t是一种无符号整数类型,一般在表示对象大小和数组的索引里使用。

posted @ 2025-11-25 22:37  鱼籽不煮粥  阅读(6)  评论(1)    收藏  举报