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 }

 

运行截图:

task1

 

问题:

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 }

 

运行截图:

task2

 

问题:

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 }

 

运行截图:

task3

 

问题:

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 }

 

运行截图:

task4

 

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 }

 

运行截图:

task5

 

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

posted on 2025-11-25 19:52  安宁的空白  阅读(6)  评论(0)    收藏  举报