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

问题:
1.是组合关系
2.(1)优点是在增加完接口以后程序会更灵活;风险是不再封闭,安全性下降
(2)public主要是面向程序外面使用,private是面象程序内部的其他内容使用,说白了就是内部实现细节
3.接口一更加安全,且效率大概率会更高一些,接口二完败
4.能运行,且更改完以后的运行效率更高
task2:
源代码:
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 }
运行截图:

问题:
1.第一行完成了带有参数的函数构造,第二行完成了拷贝函数的构造。v1与v2均含有5个42
2.三者分别问2,2,3
3.更改后可以实现相同效果
原本的代码更安全,at()函数会做越界的处理,程序跟安全;更改后的代码虽然有可能造成越界的与运行失败,但是效率提升了
(1)可以,原因是at()的那个函数会把v1放回vector,后续的push会把-1放回到末尾输出
(2)优势是内存小,缺点是const函数不允许修改他带的参数
5.(1)深复制
(2)分别返回int&,const int&;at()必须携带const的重载函数
tas3:
源代码:
1 #pragma once 2 #include <iostream> 3 4 class vectorInt{ 5 public: 6 vectorInt(); 7 vectorInt(int n_); 8 vectorInt(int n_, int value); 9 vectorInt(const vectorInt &vi); 10 ~vectorInt(); 11 12 int size() const; 13 int& at(int index); 14 const int& at(int index) const; 15 vectorInt& assign(const vectorInt &vi); 16 17 int* begin(); 18 int* end(); 19 const int* begin() const; 20 const int* end() const; 21 22 private: 23 int n; 24 int *ptr; 25 }; 26 27 vectorInt::vectorInt():n{0}, ptr{nullptr} { 28 } 29 30 vectorInt::vectorInt(int n_): n{n_}, ptr{new int[n]} { 31 } 32 33 vectorInt::vectorInt(int n_, int value): n{n_}, ptr{new int[n_]} { 34 for(auto i = 0; i < n; ++i) 35 ptr[i] = value; 36 } 37 38 vectorInt::vectorInt(const vectorInt &vi): n{vi.n}, ptr{new int[n]} { 39 for(auto i = 0; i < n; ++i) 40 ptr[i] = vi.ptr[i]; 41 } 42 43 vectorInt::~vectorInt() { 44 delete [] ptr; 45 } 46 47 int vectorInt::size() const { 48 return n; 49 } 50 51 const int& vectorInt::at(int index) const { 52 if(index < 0 || index >= n) { 53 std::cerr << "IndexError: index out of range\n"; 54 std::exit(1); 55 } 56 57 return ptr[index]; 58 } 59 60 int& vectorInt::at(int index) { 61 if(index < 0 || index >= n) { 62 std::cerr << "IndexError: index out of range\n"; 63 std::exit(1); 64 } 65 66 return ptr[index]; 67 } 68 69 vectorInt& vectorInt::assign(const vectorInt &vi) { 70 if(this == &vi) 71 return *this; 72 73 int *ptr_tmp; 74 ptr_tmp = new int[vi.n]; 75 for(int i = 0; i < vi.n; ++i) 76 ptr_tmp[i] = vi.ptr[i]; 77 78 delete[] ptr; 79 n = vi.n; 80 ptr = ptr_tmp; 81 return *this; 82 } 83 84 int* vectorInt::begin() { 85 return ptr; 86 } 87 88 int* vectorInt::end() { 89 return ptr+n; 90 } 91 92 const int* vectorInt::begin() const { 93 return ptr; 94 } 95 96 const int* vectorInt::end() const { 97 return ptr+n; 98 }
运行截图:

问题:
1.自身赋值的检查代码被删去了;参数状态发生了改变,可能会导致后面的接口发生错误
2.(1)将非const类型的this指针显式转换为const类型的vectorint*
转换之前是vectorint*,转换后是const vectorint*;目的是避免跨界访问
(2)去除const的限定,之前是const int&,修改后变成int&;目的是删除const使得参数引用允许被修改
3.v1调用int*;v2调用const int*;v1适用于不被修改的,v2反之
4.可以使用代码库里的函数;三个函数分别用于初始化,深复制,保护释放内存时v1的安全
task4:
源代码:
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 <cstdlib> 4 5 Matrix::Matrix(int rows_, int cols_, double value) 6 : n_rows(rows_), n_cols(cols_), ptr(new double[rows_ * cols_]) { 7 if (rows_ <= 0 || cols_ <= 0) { 8 std::cerr << "Error: Invalid matrix size (rows/cols must be positive)\n"; 9 std::exit(1); 10 } 11 for (int i = 0; i < rows_ * cols_; ++i) { 12 ptr[i] = value; 13 } 14 } 15 16 Matrix::Matrix(int rows_, double value) 17 : Matrix(rows_, rows_, value) {} 18 19 Matrix::Matrix(const Matrix &x) 20 : n_rows(x.n_rows), n_cols(x.n_cols), ptr(new double[x.n_rows * x.n_cols]) { 21 for (int i = 0; i < n_rows * n_cols; ++i) { 22 ptr[i] = x.ptr[i]; 23 } 24 } 25 26 Matrix::~Matrix() { 27 delete[] ptr; 28 } 29 30 void Matrix::set(const double *pvalue, int size) { 31 if (pvalue == nullptr) { 32 std::cerr << "Error: Null pointer input for set function.\n"; 33 std::exit(1); 34 } 35 if (size != n_rows * n_cols) { 36 std::cerr << "Error: Data size mismatch (expected " << n_rows * n_cols << ", got " << size << ")\n"; 37 std::exit(1); 38 } 39 for (int i = 0; i < size; ++i) { 40 ptr[i] = pvalue[i]; 41 } 42 } 43 44 void Matrix::clear() { 45 for (int i = 0; i < n_rows * n_cols; ++i) { 46 ptr[i] = 0.0; 47 } 48 } 49 50 const double& Matrix::at(int i, int j) const { 51 if (i < 0 || i >= n_rows || j < 0 || j >= n_cols) { 52 std::cerr << "IndexError: Matrix index (" << i << "," << j << ") out of range\n"; 53 std::exit(1); 54 } 55 return ptr[i * n_cols + j]; 56 } 57 58 double& Matrix::at(int i, int j) { 59 return const_cast<double&>(static_cast<const Matrix*>(this)->at(i, j)); 60 } 61 62 int Matrix::rows() const { 63 return n_rows; 64 } 65 66 int Matrix::cols() const { 67 return n_cols; 68 } 69 70 void Matrix::print() const { 71 for (int i = 0; i < n_rows; ++i) { 72 for (int j = 0; j < n_cols; ++j) { 73 if (j > 0) { 74 std::cout << ","; 75 } 76 std::cout << ptr[i * n_cols + j]; 77 } 78 std::cout << "\n"; 79 } 80 }
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 }
运行截图:

task5:
源代码:
1 #pragma once 2 #include <iostream> 3 #include <string> 4 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 }
1 # pragma once 2 #include <iostream> 3 #include <string> 4 #include <vector> 5 #include <algorithm> 6 #include "contact.hpp" 7 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; // 返回联系人在contacts内索引,如不存在,返回-1 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 // 待补足1:int index(const std::string &name) const;实现 72 // 返回联系人在contacts内索引; 如不存在,返回-1 73 int ContactBook::index(const std::string &name) const { 74 for (size_t i = 0; i < contacts.size(); ++i) { 75 if (contacts[i].get_name() == name) { 76 //比较区分大小写 77 return static_cast<int>(i); 78 } 79 } 80 return -1; 81 } 82 83 84 // 待补足2:void ContactBook::sort();实现 85 // 按姓名字典序升序排序通讯录 86 void ContactBook::sort() { 87 std::sort(contacts.begin(), contacts.end(), 88 [](const Contact &a, const Contact &b) { 89 return a.get_name() < b.get_name(); 90 }); 91 }
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 }
运行截图:

总结:好难啊,三个验证性实验虽然都很典型,后面两个实验也都用到了,但是真正把前两个代码看懂确实很费劲,特别是参数类型在返回与传递时的改变很令人头疼,task3的关于编译器选择重载函数问题很实用。task4里面rew_index等于m.rows时索引应该会越界,但是可以运行,output程序被忽略了,at()的行为ai解释为没定义,好像有点问题。task5里添加了两个私有成员函数,实现起来比较简单。
浙公网安备 33010602011771号