实验3
试验任务1:
源代码:
button.hpp:
1 #pragma once 2 3 #include <iostream> 4 #include <string> 5 6 class Button 7 { 8 public: 9 Button(const std::string &label_); 10 const std::string &get_label() const; 11 void click(); 12 13 private: 14 std::string label; 15 }; 16 17 Button::Button(const std::string &label_) : label{label_} 18 { 19 } 20 21 inline const std::string &Button::get_label() const 22 { 23 return label; 24 } 25 26 inline void Button::click() 27 { 28 std::cout << "Button '" << label << "' clicked\n"; 29 }
window.hpp:
1 #pragma once 2 3 #include <iostream> 4 #include <vector> 5 #include <algorithm> 6 #include "button.hpp" 7 8 // 窗口类 9 class Window 10 { 11 public: 12 Window(const std::string &title_); 13 void display() const; 14 void close(); 15 void add_button(const std::string &label); 16 void click_button(const std::string &label); 17 18 private: 19 bool has_button(const std::string &label) const; 20 21 private: 22 std::string title; 23 std::vector<Button> buttons; 24 }; 25 26 Window::Window(const std::string &title_) : title{title_} 27 { 28 buttons.push_back(Button("close")); 29 } 30 31 inline void Window::display() const 32 { 33 std::string s(40, '*'); 34 std::cout << s << std::endl; 35 std::cout << "window : " << title << std::endl; 36 int cnt = 0; 37 for (const auto &button : buttons) 38 std::cout << ++cnt << ". " << button.get_label() << std::endl; 39 std::cout << s << std::endl; 40 } 41 42 inline void Window::close() 43 { 44 std::cout << "close window '" << title << "'" << std::endl; 45 click_button("close"); 46 } 47 48 inline bool Window::has_button(const std::string &label) const 49 { 50 for (const auto &button : buttons) 51 if (button.get_label() == label) 52 return true; 53 54 return false; 55 } 56 57 inline void Window::add_button(const std::string &label) 58 { 59 if (has_button(label)) 60 std::cout << "button " << label << " already exists!\n"; 61 else 62 buttons.push_back(Button(label)); 63 } 64 65 inline void Window::click_button(const std::string &label) 66 { 67 for (auto &button : buttons) 68 if (button.get_label() == label) 69 { 70 button.click(); 71 return; 72 } 73 74 std::cout << "no button: " << label << std::endl; 75 }
task1.cpp:
1 #include "window.hpp" 2 #include <iostream> 3 #include <windows.h> 4 5 void test() 6 { 7 Window w("Demo"); 8 w.add_button("add"); 9 w.add_button("remove"); 10 w.add_button("modify"); 11 w.add_button("add"); 12 w.display(); 13 w.close(); 14 } 15 16 int main() 17 { 18 SetConsoleOutputCP(CP_UTF8); 19 std::cout << "用组合类模拟简单GUI:\n"; 20 test(); 21 }
运行结果:

1 #include <iostream> 2 #include <vector> 3 #include <windows.h> 4 5 void test1(); 6 void test2(); 7 void output1(const std::vector<int> &v); 8 void output2(const std::vector<int> &v); 9 void output3(const std::vector<std::vector<int>> &v); 10 11 int main() 12 { 13 SetConsoleOutputCP(CP_UTF8); 14 std::cout << "深复制验证1: 标准库vector<int>\n"; 15 test1(); 16 17 std::cout << "\n深复制验证2: 标准库vector<int>嵌套使用\n"; 18 test2(); 19 } 20 21 void test1() 22 { 23 std::vector<int> v1(5, 42); 24 const std::vector<int> v2(v1); 25 26 std::cout << "**********拷贝构造后**********\n"; 27 std::cout << "v1: "; 28 output1(v1); 29 std::cout << "v2: "; 30 output1(v2); 31 32 v1.at(0) = -1; 33 34 std::cout << "**********修改v1[0]后**********\n"; 35 std::cout << "v1: "; 36 output1(v1); 37 std::cout << "v2: "; 38 output1(v2); 39 } 40 41 void test2() 42 { 43 std::vector<std::vector<int>> v1{{1, 2, 3}, {4, 5, 6, 7}}; 44 const std::vector<std::vector<int>> v2(v1); 45 46 std::cout << "**********拷贝构造后**********\n"; 47 std::cout << "v1: "; 48 output3(v1); 49 std::cout << "v2: "; 50 output3(v2); 51 52 v1.at(0).push_back(-1); 53 54 std::cout << "**********修改v1[0]后**********\n"; 55 std::cout << "v1: \n"; 56 output3(v1); 57 std::cout << "v2: \n"; 58 output3(v2); 59 } 60 61 // 使用xx.at()+循环输出vector<int>数据项 62 void output1(const std::vector<int> &v) 63 { 64 if (v.size() == 0) 65 { 66 std::cout << '\n'; 67 return; 68 } 69 70 std::cout << v.at(0); 71 for (auto i = 1; i < v.size(); ++i) 72 std::cout << ", " << v.at(i); 73 std::cout << '\n'; 74 } 75 76 // 使用迭代器+循环输出vector<int>数据项 77 void output2(const std::vector<int> &v) 78 { 79 if (v.size() == 0) 80 { 81 std::cout << '\n'; 82 return; 83 } 84 85 auto it = v.begin(); 86 std::cout << *it; 87 88 for (it = v.begin() + 1; it != v.end(); ++it) 89 std::cout << ", " << *it; 90 std::cout << '\n'; 91 } 92 93 // 使用auto for分行输出vector<vector<int>>数据项 94 void output3(const std::vector<std::vector<int>> &v) 95 { 96 if (v.size() == 0) 97 { 98 std::cout << '\n'; 99 return; 100 } 101 102 for (auto &i : v) 103 output2(i); 104 }
运行结果:

问题回答:
1.std::vector<int> v1(5, 42)构造了5个值为42的元素(int类型),是带参数的构造函数,const std::vector<int> v2(v1)是复制构造函数;都含5个值为42的元素。
2.v1.size()和v2.size()都为2,v1[0].size()为3。
3.效果相同,但是v1.at(0)=-1会做越界检查并抛出异常,而v1.[0]=-1不会。
4.(1)能。 v1.at(0)返回vector<int>&,执行完v1.at(0).push_back(-1)后,此时r的最后一个就是-1。
(2)const&避免拷贝,节省了内存,是只读,不可修改被引用对象;但是只能调用const成员对象。
5.(1)深复制。
(2)当 v 是 vector<int> 时, v.at(0) 返回值类型是int&;当 v 是 const vector<int> 时, v.at(0) 返回值类型是const int&;必须提供带 const 修饰的重载版本。
试验任务3:
1 #pragma once 2 3 #include <iostream> 4 5 // 动态int数组对象类 6 class vectorInt 7 { 8 public: 9 vectorInt(); 10 vectorInt(int n_); 11 vectorInt(int n_, int value); 12 vectorInt(const vectorInt &vi); 13 ~vectorInt(); 14 15 int size() const; 16 int &at(int index); 17 const int &at(int index) const; 18 vectorInt &assign(const vectorInt &vi); 19 20 int *begin(); 21 int *end(); 22 const int *begin() const; 23 const int *end() const; 24 25 private: 26 int n; // 当前数据项个数 27 int *ptr; // 数据区 28 }; 29 30 vectorInt::vectorInt() : n{0}, ptr{nullptr} 31 { 32 } 33 34 vectorInt::vectorInt(int n_) : n{n_}, ptr{new int[n]} 35 { 36 } 37 38 vectorInt::vectorInt(int n_, int value) : n{n_}, ptr{new int[n_]} 39 { 40 for (auto i = 0; i < n; ++i) 41 ptr[i] = value; 42 } 43 44 vectorInt::vectorInt(const vectorInt &vi) : n{vi.n}, ptr{new int[n]} 45 { 46 for (auto i = 0; i < n; ++i) 47 ptr[i] = vi.ptr[i]; 48 } 49 50 vectorInt::~vectorInt() 51 { 52 delete[] ptr; 53 } 54 55 int vectorInt::size() const 56 { 57 return n; 58 } 59 60 const int &vectorInt::at(int index) const 61 { 62 if (index < 0 || index >= n) 63 { 64 std::cerr << "IndexError: index out of range\n"; 65 std::exit(1); 66 } 67 68 return ptr[index]; 69 } 70 71 int &vectorInt::at(int index) 72 { 73 if (index < 0 || index >= n) 74 { 75 std::cerr << "IndexError: index out of range\n"; 76 std::exit(1); 77 } 78 79 return ptr[index]; 80 } 81 82 vectorInt &vectorInt::assign(const vectorInt &vi) 83 { 84 if (this == &vi) 85 return *this; 86 87 int *ptr_tmp; 88 ptr_tmp = new int[vi.n]; 89 for (int i = 0; i < vi.n; ++i) 90 ptr_tmp[i] = vi.ptr[i]; 91 92 delete[] ptr; 93 n = vi.n; 94 ptr = ptr_tmp; 95 return *this; 96 } 97 98 int *vectorInt::begin() 99 { 100 return ptr; 101 } 102 103 int *vectorInt::end() 104 { 105 return ptr + n; 106 } 107 108 const int *vectorInt::begin() const 109 { 110 return ptr; 111 } 112 113 const int *vectorInt::end() const 114 { 115 return ptr + n; 116 }
1 #include "vectorInt.hpp" 2 #include <iostream> 3 #include <windows.h> 4 5 void test1(); 6 void test2(); 7 void output1(const vectorInt &vi); 8 void output2(const vectorInt &vi); 9 10 int main() 11 { 12 SetConsoleOutputCP(CP_UTF8); 13 std::cout << "测试1: \n"; 14 test1(); 15 16 std::cout << "\n测试2: \n"; 17 test2(); 18 } 19 20 void test1() 21 { 22 int n; 23 std::cout << "Enter n: "; 24 std::cin >> n; 25 26 vectorInt x1(n); 27 for (auto i = 0; i < n; ++i) 28 x1.at(i) = (i + 1) * 10; 29 std::cout << "x1: "; 30 output1(x1); 31 32 vectorInt x2(n, 42); 33 vectorInt x3(x2); 34 x2.at(0) = -1; 35 std::cout << "x2: "; 36 output1(x2); 37 std::cout << "x3: "; 38 output1(x3); 39 } 40 41 void test2() 42 { 43 const vectorInt x(5, 42); 44 vectorInt y; 45 46 y.assign(x); 47 48 std::cout << "x: "; 49 output2(x); 50 std::cout << "y: "; 51 output2(y); 52 } 53 54 // 使用xx.at()+循环输出vectorInt对象数据项 55 void output1(const vectorInt &vi) 56 { 57 if (vi.size() == 0) 58 { 59 std::cout << '\n'; 60 return; 61 } 62 63 std::cout << vi.at(0); 64 for (auto i = 1; i < vi.size(); ++i) 65 std::cout << ", " << vi.at(i); 66 std::cout << '\n'; 67 } 68 69 // 使用迭代器+循环输出vectorInt对象数据项 70 void output2(const vectorInt &vi) 71 { 72 if (vi.size() == 0) 73 { 74 std::cout << '\n'; 75 return; 76 } 77 78 auto it = vi.begin(); 79 std::cout << *it; 80 81 for (it = vi.begin() + 1; it != vi.end(); ++it) 82 std::cout << ", " << *it; 83 std::cout << '\n'; 84 }
运行结果:

问题回答:
1.assign的版本2没有进行是否是自赋值的判断。如果是自赋值的话,一开始就释放数据,会导致数据异常释放,无法完成相关操作。
2.(1)static_cast<const vectorInt*>(this)把this类型从vectorInt*转换为const vectorInt*;
转换前:vectorInt*,转换后:const vectorInt*;
其目的是为了能够调用 at 函数的 const 版本。
(2) const_cast<int&>是为了去除const;
转换前:const int&;转换后:int&;
目的是为了移除const限定,同时返回int&类型。
3.(1)v1调用非const接口,适用于需要修改元素;v2调用const接口,适用于仅读取,不修改对象状态。
4.可以。std::fill_n(ptr, n, value)表示从ptr指向的位置开始,连续填充n个值为value的数据;
std::copy_n(vi.ptr, vi.n, ptr)表示从vi.ptr开始,连续复制n个值给ptr;
试验任务4:
1 #pragma once 2 3 #include <iostream> 4 #include <algorithm> 5 #include <cstdlib> 6 7 // 类Matrix声明 8 class Matrix 9 { 10 public: 11 Matrix(int rows_, int cols_, double value = 0); // 构造rows_*cols_矩阵对象, 初值value 12 Matrix(int rows_, double value = 0); // 构造rows_*rows_方阵对象, 初值value 13 Matrix(const Matrix &x); // 深复制 14 ~Matrix(); 15 16 void set(const double *pvalue, int size); // 按行复制pvalue指向的数据,要求size=rows*cols,否则报错退出 17 void clear(); // 矩阵对象数据项置0 18 19 const double &at(int i, int j) const; // 返回矩阵对象索引(i,j)对应的数据项const引用(越界则报错后退出) 20 double &at(int i, int j); // 返回矩阵对象索引(i,j)对应的数据项引用(越界则报错后退出) 21 22 int rows() const; // 返回矩阵对象行数 23 int cols() const; // 返回矩阵对象列数 24 25 void print() const; // 按行打印数据 26 27 private: 28 int n_rows; // 矩阵对象内元素行数 29 int n_cols; // 矩阵对象内元素列数 30 double *ptr; // 数据区 31 }; 32 33 Matrix::Matrix(int rows_, int cols_, double value): n_rows(rows_), n_cols(cols_) 34 { 35 ptr = new double[n_rows * n_cols]; 36 std::fill(ptr, ptr + n_rows * n_cols, value); 37 } 38 39 Matrix::Matrix(int rows_, double value): Matrix(rows_, rows_, value) 40 { 41 } 42 43 Matrix::Matrix(const Matrix &x): n_rows(x.n_rows), n_cols(x.n_cols) 44 { 45 ptr = new double[n_rows * n_cols]; 46 std::copy(x.ptr, x.ptr + n_rows * n_cols, ptr); 47 } 48 49 Matrix::~Matrix() 50 { 51 delete[] ptr; 52 } 53 54 void Matrix::set(const double *pvalue, int size) 55 { 56 if (size != n_rows * n_cols) 57 { 58 std::cerr << "ERROR!" << std::endl; 59 std::exit(-1); 60 } 61 std::copy(pvalue, pvalue + size, ptr); 62 } 63 64 void Matrix::clear() 65 { 66 std::fill(ptr, ptr + n_rows * n_cols, 0); 67 } 68 69 double &Matrix::at(int i, int j) 70 { 71 return const_cast<double &>(static_cast<const Matrix *>(this)->at(i, j)); 72 } 73 74 const double &Matrix::at(int i, int j) const 75 { 76 if (i < 0 || i >= n_rows || j < 0 || j >= n_cols) 77 { 78 std::cerr << "IndexError: index out of range\n"; 79 std::exit(1); 80 } 81 return ptr[i * n_cols + j]; 82 } 83 84 int Matrix::rows() const 85 { 86 return n_rows; 87 } 88 89 int Matrix::cols() const 90 { 91 return n_cols; 92 } 93 94 void Matrix::print() const 95 { 96 for (int i = 0; i < n_rows; ++i) 97 { 98 for (int j = 0; j < n_cols; ++j) 99 { 100 std::cout << at(i, j) << " "; 101 } 102 std::cout << "\n"; 103 } 104 }
task4.cpp:
1 #include <iostream> 2 #include <cstdlib> 3 #include "matrix.hpp" 4 #include <windows.h> 5 6 void test1(); 7 void test2(); 8 void output(const Matrix &m, int row_index); 9 10 int main() 11 { 12 SetConsoleOutputCP(CP_UTF8); 13 std::cout << "测试1: \n"; 14 test1(); 15 16 std::cout << "\n测试2: \n"; 17 test2(); 18 } 19 20 void test1() 21 { 22 double x[1000] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 23 24 int n, m; 25 std::cout << "Enter n and m: "; 26 std::cin >> n >> m; 27 28 Matrix m1(n, m); // 创建矩阵对象m1, 大小n×m 29 m1.set(x, n * m); // 用一维数组x的值按行为矩阵m1赋值 30 31 Matrix m2(m, n); // 创建矩阵对象m2, 大小m×n 32 m2.set(x, m * n); // 用一维数组x的值按行为矩阵m1赋值 33 34 Matrix m3(n); // 创建一个n×n方阵对象 35 m3.set(x, n * n); // 用一维数组x的值按行为矩阵m3赋值 36 37 std::cout << "矩阵对象m1: \n"; 38 m1.print(); 39 std::cout << "矩阵对象m2: \n"; 40 m2.print(); 41 std::cout << "矩阵对象m3: \n"; 42 m3.print(); 43 } 44 45 void test2() 46 { 47 Matrix m1(2, 3, -1); 48 const Matrix m2(m1); 49 50 std::cout << "矩阵对象m1: \n"; 51 m1.print(); 52 std::cout << "矩阵对象m2: \n"; 53 m2.print(); 54 55 m1.clear(); 56 m1.at(0, 0) = 1; 57 58 std::cout << "m1更新后: \n"; 59 std::cout << "矩阵对象m1第0行 "; 60 output(m1, 0); 61 std::cout << "矩阵对象m2第0行: "; 62 output(m2, 0); 63 } 64 65 // 输出矩阵对象row_index行所有元素 66 void output(const Matrix &m, int row_index) 67 { 68 if (row_index < 0 || row_index >= m.rows()) 69 { 70 std::cerr << "IndexError: row index out of range\n"; 71 exit(1); 72 } 73 74 std::cout << m.at(row_index, 0); 75 for (int j = 1; j < m.cols(); ++j) 76 std::cout << ", " << m.at(row_index, j); 77 std::cout << '\n'; 78 }
运行结果:

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


浙公网安备 33010602011771号