实验任务一:
问题1:
答:是组合关系,Button对象是WIndow对象的组成部分。
问题2:
答:(1)优点:用户可以调用函数判断窗口中是否有某按钮,帮助用户了解窗口。
缺点:接口变大了,用户可能会使用has_button接口自己去实现一些判断,但是如果后续类的设计出现其他改动可能会导致用户的逻辑无法实现原有功能,而将has_button设计成private不给用户访问,使得接口最小化,可以在今后的改动中最大限度的使得只改动类的内部而不影响原有代码的功能。
(2)在设计时我们始终秉持一个原则,在满足用户需要的前提下,尽可能使得接口尽量的小,是封装性发更强,拓展性更强。比如,如果用户确实需要的,设计成public,如果只在类的内部使用用户完全不需要使用的,就设计成private。
问题3:
答:接口一返回string对象的常引用相较接口儿避免调用复制构造函数,节省不必要的开销,同时,因为避免了复制构造函数的调用,也就避免了深浅复制处理不当导致的安全性问题。
问题四:
答:能正常运行。xx.push_back(Button(xxx))是调用构造函数生成临时对象作为实参去调用函数,期间总共调用了构造函数和复制构造函两个函数,而xx.emplace_back(xxx)直接在 vector 末尾的内存空间中原地构造元素,仅需传入构造函数的参数,无需临时对象,避免了不必要的额外开销。

实验任务三:
问题1:
答:v1是数据元素的int型的动态数组,v2是数据元素是数据元素是int型的vector的动态数组,即v2的每个元素都是一个vector<int>。v1有1个,v2有0个。
问题2:
答:v1.size() = 2 ;v2.size() = 1 ;v1[0].size() = 3。
问题3:
答:能实现相同效果。使用xx.at()函数会检查边界,若请求访问的下标越界则会报错,而使用[]访问即使下标越界了也会正常访问。
问题4:
答:(1)能输出-1. 因为v1是vector<vector<int>>类的对象,它的0号元素就是vector<int>类型的对象,当然可以给vector<int> &类型的变量初始化。
(2)节省内存,只需要开辟一个小内存存储引用变量,而不需要开领大空间存储完整对象。限制就是引用和原对象会操作同一片内存空间,数据只有一份。
问题5:
答:(1)深复制。
(2)返回vint &; 返回const int &;需要。C++ 中,const 对象只能调用 const 成员函数。如果 at() 没有提供 const 重载版本,那么 const vector<int> 类型的对象 v 就无法调用 at() 接口。
实验任务3:
答:(1)版本2没有自复制处理,若出现自复制,版本二上来直接就把自己的ptr删除了,后续直接全部出错。
(2)版本2是先删后建,再分配内存成功之前就先删除了原有内存,万一内存分配出错,则会导致原有数据丢失,对象就出现异常了。
问题2:
答:(1) static_cast<const vectorInt *>(this)作用是将this指针类型转换成cosnt vectorInt*类型;this转换前类型是vectorInt *类型,转换后是 const vectorInt *类型,转换成const类型用来调用常函数版本的at函数。
(2)const_cast<int&>将const int&转换成int &类型;
转换前是const int & ,转换后是 int&;因为这个版本的at函数要求返回int&类型。
问题3:
auto it1 = v1.begin(); 调用非const版本。
auto it2 = v2.begin(); 调用const版本。
问题4:
答:可行。
std::fill_n(ptr, n, value); 功能:ptr地址起n个单位的内存赋值成value。
std::copy_n(vi.ptr, vi.n, ptr); 功能:将[ptr ,ptr+n)区间的值复制到ptr为起点的连续空间。
实验任务四:
1 #pragma once 2 3 #include <iostream> 4 #include <algorithm> 5 #include <cstdlib> 6 7 // 类Matrix声明 8 class Matrix { 9 public: 10 Matrix(int rows_, int cols_, double value = 0); // 构造rows_*cols_矩阵对象, 初值value 11 Matrix(int rows_, double value = 0); // 构造rows_*rows_方阵对象, 初值value 12 Matrix(const Matrix &x); // 深复制 13 ~Matrix(); 14 15 void set(const double *pvalue, int size); // 按行复制pvalue指向的数据,要求size=rows*cols,否则报错退出 16 void clear(); // 矩阵对象数据项置0 17 18 const double& at(int i, int j) const; // 返回矩阵对象索引(i,j)对应的数据项const引用(越界则报错后退出) 19 double& at(int i, int j); // 返回矩阵对象索引(i,j)对应的数据项引用(越界则报错后退出) 20 21 int rows() const; // 返回矩阵对象行数 22 int cols() const; // 返回矩阵对象列数 23 24 void print() const; // 按行打印数据 25 26 private: 27 int n_rows; // 矩阵对象内元素行数 28 int n_cols; // 矩阵对象内元素列数 29 double *ptr; // 数据区 30 };
1 #include"matrix.hpp" 2 #include<iostream> 3 #include<stdlib.h> 4 Matrix::Matrix(int rows_, int cols_, double value) 5 { 6 n_rows = rows_; 7 n_cols = cols_; 8 ptr = new double[rows_ * cols_]; 9 for (int i = 0; i < rows_ * cols_; i++) 10 *(ptr + i) = value; 11 } 12 Matrix::Matrix(int rows_ ,double value) 13 { 14 n_rows = rows_; 15 n_cols = rows_; 16 ptr = new double[rows_ * rows_]; 17 for (int i = 0; i < rows_ * rows_; i++) 18 *(ptr + i) = value; 19 } 20 Matrix::Matrix(const Matrix& x) 21 { 22 n_rows = x.n_rows; 23 n_cols = x.n_cols; 24 ptr = new double[n_cols * n_rows]; 25 for (int i = 0; i < n_cols * n_rows; i++) 26 *(ptr + i) = *(x.ptr + i); 27 } 28 Matrix::~Matrix() 29 { 30 delete[]ptr; 31 } 32 void Matrix::set(const double* pvalue, int size) 33 { 34 if (size != n_cols * n_rows) 35 exit(0); 36 else 37 { 38 for (int i = 0; i < size; i++) 39 *(ptr + i) = *(pvalue + i); 40 } 41 } 42 void Matrix::clear() 43 { 44 for (int i = 0; i < n_rows * n_cols; i++) 45 *(ptr + i) = 0; 46 } 47 const double& Matrix::at(int i, int j) const 48 { 49 int pos = i * n_cols + j; 50 if (pos < 0 || pos >= n_cols * n_rows) 51 { 52 std::cout << "越界访问!\n"; 53 exit(0); 54 } 55 else 56 return *(ptr + pos); 57 58 } 59 double& Matrix::at(int i, int j) 60 { 61 return const_cast<double&>(static_cast<const Matrix*>(this)->at(i, j)); 62 } 63 int Matrix::rows() const 64 { 65 return n_rows; 66 } 67 int Matrix::cols() const 68 { 69 return n_cols; 70 } 71 void Matrix::print() const 72 { 73 int num = 0; 74 for (int i = 0; i < n_cols * n_rows; i++) 75 { 76 std::cout << *(ptr + i) << ' '; 77 num++; 78 if (num % n_cols == 0) 79 std::cout << '\n'; 80 } 81 }
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); // 创建矩阵对象m1, 大小n×m 25 m1.set(x, n*m); // 用一维数组x的值按行为矩阵m1赋值 26 27 Matrix m2(m, n); // 创建矩阵对象m2, 大小m×n 28 m2.set(x, m*n); // 用一维数组x的值按行为矩阵m1赋值 29 30 Matrix m3(n); // 创建一个n×n方阵对象 31 m3.set(x, n*n); // 用一维数组x的值按行为矩阵m3赋值 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 // 输出矩阵对象row_index行所有元素 54 void output(const Matrix &m, int row_index) { 55 if(row_index < 0 || row_index >= m.rows()) { 56 std::cerr << "IndexError: row index out of range\n"; 57 exit(1); 58 } 59 60 std::cout << m.at(row_index, 0); 61 for(int j = 1; j < m.cols(); ++j) 62 std::cout << ", " << m.at(row_index, j); 63 std::cout << '\n'; 64 }

实验任务五:
答:
1 #pragma once 2 3 #include <iostream> 4 #include <string> 5 6 // 联系人类 7 class Contact { 8 public: 9 Contact(const std::string &name_, const std::string &phone_); 10 11 const std::string &get_name() const; 12 const std::string &get_phone() const; 13 void display() const; 14 15 private: 16 std::string name; // 必填项 17 std::string phone; // 必填项 18 }; 19 20 Contact::Contact(const std::string &name_, const std::string &phone_):name{name_}, phone{phone_} { 21 } 22 23 const std::string& Contact::get_name() const { 24 return name; 25 } 26 27 const std::string& Contact::get_phone() const { 28 return phone; 29 } 30 31 void Contact::display() const { 32 std::cout << name << ", " << phone; 33 }
1 # pragma once 2 3 #include <iostream> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include "contact.hpp" 8 9 // 通讯录类 10 class ContactBook { 11 public: 12 void add(const std::string &name, const std::string &phone); // 添加联系人 13 void remove(const std::string &name); // 移除联系人 14 void find(const std::string &name) const; // 查找联系人 15 void display() const; // 显示所有联系人 16 size_t size() const; 17 18 private: 19 int index(const std::string &name) const; // 返回联系人在contacts内索引,如不存在,返回-1 20 void sort(); // 按姓名字典序升序排序通讯录 21 22 private: 23 std::vector<Contact> contacts; 24 }; 25 26 void ContactBook::add(const std::string &name, const std::string &phone) { 27 if(index(name) == -1) { 28 contacts.push_back(Contact(name, phone)); 29 std::cout << name << " add successfully.\n"; 30 sort(); 31 return; 32 } 33 34 std::cout << name << " already exists. fail to add!\n"; 35 } 36 37 void ContactBook::remove(const std::string &name) { 38 int i = index(name); 39 40 if(i == -1) { 41 std::cout << name << " not found, fail to remove!\n"; 42 return; 43 } 44 45 contacts.erase(contacts.begin()+i); 46 std::cout << name << " remove successfully.\n"; 47 } 48 49 void ContactBook::find(const std::string &name) const { 50 int i = index(name); 51 52 if(i == -1) { 53 std::cout << name << " not found!\n"; 54 return; 55 } 56 57 contacts[i].display(); 58 std::cout << '\n'; 59 } 60 61 void ContactBook::display() const { 62 for(auto &c: contacts) { 63 c.display(); 64 std::cout << '\n'; 65 } 66 } 67 68 size_t ContactBook::size() const { 69 return contacts.size(); 70 } 71 72 // 待补足1:int index(const std::string &name) const;实现 73 // 返回联系人在contacts内索引; 如不存在,返回-1 74 int ContactBook::index(const std::string& name) const 75 { 76 for (int i = 0; i < contacts.size();i++) 77 { 78 if (name == contacts[i].get_name()) 79 return i; 80 } 81 return -1; 82 } 83 84 85 86 // 待补足2:void ContactBook::sort();实现 87 // 按姓名字典序升序排序通讯录 88 void ContactBook::sort() 89 { 90 int i, j, k = 0; 91 for (i = 0; i < contacts.size() - 1; i++) 92 { 93 k = i; 94 for (j = i + 1; j < contacts.size(); j++) 95 { 96 if (contacts[k].get_name() > contacts[j].get_name()) 97 k = j; 98 } 99 if (k != i) 100 { 101 Contact temp = contacts[k]; 102 contacts[k] = contacts[i]; 103 contacts[i] = temp; 104 } 105 } 106 107 }
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 }

实验总结:
功能相同的const与非const成员函数通过static_cast和const_cast可以用一个函数实现两个函数,减少接口。