实验3

##实验任务1

#代码

 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_lab() const;
11     void click();
12  
13 private:
14     std::string label;
15 };
16  
17 inline const std::string& Button::get_lab() const {
18     return label;
19 }
20  
21 inline void Button::click() {
22     std::cout << "Button '" << label << "' clicked\n";
23 }
24  
 1 #pragma once
 2  
 3 #include <iostream>
 4 #include <vector>
 5 #include <algorithm>
 6 #include <string>
 7  
 8 #include "Button.h"
 9  
10 class Window
11 {
12 public:
13     Window(const std::string& title_);
14  
15     void display() const;
16     void close();
17     void add_button(const std::string& label);
18     void click_button(const std::string& label);
19  
20 private:
21     bool has_button(const std::string& label) const;
22  
23 private:
24     std::string title;
25     std::vector<Button> buttons;
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_lab() << 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_lab() == 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_lab() == label) {
61             button.click();
62             return;
63         }
64     std::cout << "no button: " << label << std::endl;
65 }
 1 #include "Window.h"
 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 }

#运行结果

image

 

##问题

1.是,Window类包含Button对象作为成员。

2.(1)优点:外部可以查询窗口是否包含特定按钮;风险:破坏了封装性,存在误用风险。

(2)用户需求:用户是否需要直接调用这个功能;

封装性:是否是内部实现细节;状态安全:是否会破坏对象的不变性或内部状态。

3.接口1返回引用,避免字符串拷贝,性能更好;

接口2返回的是副本,生命周期独立,更安全。

4.正常运行,push_back(Button(label)),创建临时对象,就并且调用结束后临时对象被销毁;emplace_back(label),直接在vector的内存空间中构造Button对象,避免临时对象的创建和销毁。

##实验任务2

#代码

 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 //验证vector<int>的深复制
19 //拷贝后未修改原容器,仅展示拷贝结果
20 void test1() {
21     std::vector<int> v1(5, 42);    //v1:42,42,42,42,42
22     const std::vector<int> v2(v1);
23  
24     std::cout << "**********拷贝构造后**********\n";
25     std::cout << "v1: ";
26     output1(v1);
27     std::cout << "v2: ";
28     output1(v2);
29 }
30  
31 //验证vector<vector<int>>的深复制
32 //拷贝后修改原容器的子vector,观察拷贝容器是否受影响
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: "; 
39     output3(v1);
40     std::cout << "v2: "; 
41     output3(v2);
42  
43     v1.at(0).push_back(-1);
44  
45     std::cout << "**********修改v1[0]后**********\n";
46     std::cout << "v1: \n"; 
47     output3(v1);
48     std::cout << "v2: \n"; 
49     output3(v2);
50 }
51  
52 // 使用xx.at()+循环输出vector<int>数据项
53 //v.at(i)—— 安全的元素访问方式(越界时会抛出out_of_range异常,比v[i]更安全)
54 void output1(const std::vector<int>& v) {
55     if (v.size() == 0) {
56         std::cout << '\n';
57         return;
58     }
59  
60     std::cout << v.at(0);
61     for (auto i = 1; i < v.size(); ++i)
62         std::cout << ", " << v.at(i);
63     std::cout << '\n';
64 }
65  
66 // 使用迭代器+循环输出vector<int>数据项
67 void output2(const std::vector<int>& v) {
68     if (v.size() == 0) {
69         std::cout << '\n';
70         return;
71     }
72  
73     //*it:解引用迭代器,获取它指向的元素值
74     auto it = v.begin();
75     std::cout << *it;
76  
77     for (it = v.begin() + 1; it != v.end(); ++it)
78         std::cout << ", " << *it;
79     std::cout << '\n';
80 }
81  
82 // 使用auto for分行输出vector<vector<int>>数据项
83 // 参数类型vector<vector<int>>:二维容器(容器的每个元素也是一个vector<int>)
84 void output3(const std::vector<std::vector<int>>& v) {
85     if (v.size() == 0) {
86         std::cout << '\n';
87         return;
88     }
89 // 范围 for 循环for (auto& i : v):遍历二维容器的每个元素(即每个子vector<int>)
90 // 用auto&而非auto:避免拷贝子vector,提高效率(auto会触发子容器的拷贝构造,没必要)
91     for (auto& i : v)
92         output2(i);
93 }

#运行结果

image

 

##问题

1.构造函数和拷贝构造函数; v1和v2各包含5个42。

2.2 2 3

3.可以 v1.at(0) = -1使用时更加安全;v1[0] = -1使用时存在安全风险,但是性能更好。

4.能输出 调用size()来方法返回对象长度的int值,可以输出-1

优势:避免不必要的拷贝构造,节省内存 限制:不能通过const引用修改所引用的对象,只能进行只读操作

5.(1)深复制(2)当 v 是 vector<int> 时, v.at(0) 返回值类型是int &;当 v 是 const vector<int> 时, v.at(0) 返回值类型是const int &; 是。

##实验任务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  
 1 #include "VectorInt.h"
 2  
 3 VectorInt::VectorInt() :n{ 0 },ptr{ nullptr } {
 4 }
 5  
 6 VectorInt::VectorInt(int n_) :n{ n_ }, ptr{ new int[n] } {
 7 }
 8  
 9 VectorInt::VectorInt(int n_, int value) :n{ n_ }, ptr{ new int[n_] } {
10     for (auto i = 0; i < n; i++)
11         ptr[i] = value;
12 }
13  
14 VectorInt::VectorInt(const VectorInt& vi) :n{ vi.n }, ptr{ new int[n] } {
15     for (auto i = 0; i < n; ++i)
16         ptr[i] = vi.ptr[i];
17 }
18  
19 VectorInt::~VectorInt() {
20     delete[] ptr;
21 }
22  
23 int VectorInt::size() const {
24     return n;
25 }
26  
27 const int& VectorInt::at(int index) const {
28     if (index < 0 || index >= n) {
29         std::cerr << "IndexError: index out of range\n";
30         std::exit(1);
31     }
32     return ptr[index];
33 }
34  
35 int& VectorInt::at(int index) {
36     if (index < 0 || index >= n) {
37         std::cerr << "IndexError: index out of range\n";
38         std::exit(1);
39     }
40     return ptr[index];
41 }
42  
43 VectorInt& VectorInt::assign(const VectorInt& vi) {
44     if (this == &vi)
45         return *this;
46     int* ptr_tmp;
47     ptr_tmp = new int[vi.n];
48     for (int i = 0; i < vi.n; ++i)
49         ptr_tmp[i] = vi.ptr[i];
50     delete[] ptr;
51     n = vi.n;
52     ptr = ptr_tmp;
53     return *this;
54 }
55  
56 int* VectorInt::begin() {
57     return ptr;
58 }
59  
60 int* VectorInt::end() {
61     return ptr + n;
62 }
63  
64 const int* VectorInt::begin() const {
65     return ptr;
66 }
67  
68 const int* VectorInt::end() const {
69     return ptr + n;
70 }
71  
72  
 1 #include "VectorInt.h"
 2  
 3 #include <iostream>
 4  
 5 void test1();
 6 void test2();
 7 void output1(const VectorInt& vi);
 8 void output2(const VectorInt& vi);
 9  
10 int main() {
11     std::cout << "测试1: \n";
12     test1();
13     std::cout << "\n测试2: \n";
14     test2();
15 }
16  
17 void test1() {
18     int n;
19     std::cout << "Enter n: ";
20     std::cin >> n;
21     VectorInt x1(n);
22     for (auto i = 0; i < n; ++i)
23         x1.at(i) = (i + 1) * 10;
24     std::cout << "x1: "; output1(x1);
25     VectorInt x2(n, 42);
26     VectorInt x3(x2);
27     x2.at(0) = -1;
28     std::cout << "x2: "; output1(x2);
29     std::cout << "x3: "; output1(x3);
30 }
31  
32 void test2() {
33     const VectorInt x(5, 42);
34     VectorInt y;
35     y.assign(x);
36     std::cout << "x: "; output2(x);
37     std::cout << "y: "; output2(y);
38 }
39  
40 // 使用xx.at()+循环输出VectorInt对象数据项
41 void output1(const VectorInt& vi) {
42     if (vi.size() == 0) {
43         std::cout << '\n';
44         return;
45     }
46     std::cout << vi.at(0);
47     for (auto i = 1; i < vi.size(); ++i)
48         std::cout << ", " << vi.at(i);
49     std::cout << '\n';
50 }
51  
52 // 使用迭代器+循环输出VectorInt对象数据项
53 void output2(const VectorInt& vi) {
54     if (vi.size() == 0) {
55         std::cout << '\n';
56         return;
57     }
58     auto it = vi.begin();
59     std::cout << *it;
60     for (it = vi.begin() + 1; it != vi.end(); ++it)
61         std::cout << ", " << *it;
62     std::cout << '\n';
63 }
64  

##运行结果

image

 ##问题

1.版本2缺少自赋值检查

2.(1)类型转换

转换前:vectorInt*(非const指针)  

转换后:const vectorInt*(const指针)

将当前对象转换为const版本,以便调用const版本的at()方法

(2)const_cast<int&>作用是移除const修饰符,使返回值可以用于修改操作     转换前this返回类型是const int& 转换后返回类型是int&   目的:满足非const接口的返回类型要求

3.(1)非const版本:用于需要修改容器内容的场景  const版本:用于只读访问或const对象的场景

(2)vectorInt直接返回原始指针作为迭代器,说明迭代器本质上是提供统一访问接口的抽象

4.可以,fill将ptr开始的n个元素都设置为value   copy 从vi.ptr复制n个元素到ptr

##实验任务4

#代码

 1 #pragma once
 2 
 3 class Matrix {
 4 public:
 5     Matrix(int rows_, int cols_, double value = 0);
 6     Matrix(int rows_, double value = 0);
 7     Matrix(const Matrix &x);
 8     ~Matrix();
 9     
10     void set(const double *pvalue, int size);
11     void clear();
12     const double& at(int i, int j) const;
13     double& at(int i, int j);
14     int rows() const;
15     int cols() const;
16     void print() const;
17 
18 private:
19     int n_rows;
20     int n_cols;
21     double *ptr;
22 };
 1 #include "matrix.hpp"
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <algorithm>
 5 
 6 // 构造函数:rows_×cols_矩阵
 7 Matrix::Matrix(int rows_, int cols_, double value) 
 8     : n_rows(rows_), n_cols(cols_), ptr(new double[rows_ * cols_]) {
 9     if (rows_ <= 0 || cols_ <= 0) {
10         std::cerr << "Error: Invalid matrix dimensions\n";
11         std::exit(1);
12     }
13     std::fill_n(ptr, n_rows * n_cols, value);
14 }
15 
16 // 构造函数:rows_×rows_方阵
17 Matrix::Matrix(int rows_, double value) 
18     : n_rows(rows_), n_cols(rows_), ptr(new double[rows_ * rows_]) {
19     if (rows_ <= 0) {
20         std::cerr << "Error: Invalid matrix dimensions\n";
21         std::exit(1);
22     }
23     std::fill_n(ptr, n_rows * n_cols, value);
24 }
25 
26 // 拷贝构造函数(深拷贝)
27 Matrix::Matrix(const Matrix &x) 
28     : n_rows(x.n_rows), n_cols(x.n_cols), ptr(new double[x.n_rows * x.n_cols]) {
29     std::copy(x.ptr, x.ptr + n_rows * n_cols, ptr);
30 }
31 
32 // 析构函数
33 Matrix::~Matrix() {
34     delete[] ptr;
35 }
36 
37 // 设置矩阵数据
38 void Matrix::set(const double *pvalue, int size) {
39     if (size != n_rows * n_cols) {
40         std::cerr << "Error: Size mismatch in set()\n";
41         std::exit(1);
42     }
43     std::copy(pvalue, pvalue + size, ptr);
44 }
45 
46 // 清空矩阵(置0)
47 void Matrix::clear() {
48     std::fill_n(ptr, n_rows * n_cols, 0.0);
49 }
50 
51 // 常量版本的元素访问
52 const double& Matrix::at(int i, int j) const {
53     if (i < 0 || i >= n_rows || j < 0 || j >= n_cols) {
54         std::cerr << "Error: Index out of range in at()\n";
55         std::exit(1);
56     }
57     return ptr[i * n_cols + j];
58 }
59 
60 // 非常量版本的元素访问
61 double& Matrix::at(int i, int j) {
62     if (i < 0 || i >= n_rows || j < 0 || j >= n_cols) {
63         std::cerr << "Error: Index out of range in at()\n";
64         std::exit(1);
65     }
66     return ptr[i * n_cols + j];
67 }
68 
69 // 返回行数
70 int Matrix::rows() const {
71     return n_rows;
72 }
73 
74 // 返回列数
75 int Matrix::cols() const {
76     return n_cols;
77 }
78 
79 // 打印矩阵
80 void Matrix::print() const {
81     for (int i = 0; i < n_rows; ++i) {
82         for (int j = 0; j < n_cols; ++j) {
83             std::cout << at(i, j) << " ";
84         }
85         std::cout << "\n";
86     }
87 }
 1 #include <iostream>
 2 #include <cstdlib>
 3  
 4 #include "Matrix.h"
 5  
 6 void test1();
 7 void test2();
 8 void output(const Matrix& m, int row_index);
 9  
10 int main() {
11     std::cout << "测试1: \n";
12     test1();
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     int n, m;
20     std::cout << "Enter n and m: ";
21     std::cin >> n >> m;
22  
23     Matrix m1(n, m); // 创建矩阵对象m1, 大小n×m
24     m1.set(x, n * m); // 用一维数组x的值按行为矩阵m1赋值
25  
26     Matrix m2(m, n); // 创建矩阵对象m2, 大小m×n
27     m2.set(x, m * n); // 用一维数组x的值按行为矩阵m1赋值
28  
29     Matrix m3(n); // 创建一个n×n方阵对象
30     m3.set(x, n * n); // 用一维数组x的值按行为矩阵m3赋值
31  
32     std::cout << "矩阵对象m1: \n"; m1.print();
33     std::cout << "矩阵对象m2: \n"; m2.print();
34     std::cout << "矩阵对象m3: \n"; m3.print();
35 }
36  
37 void test2() {
38     Matrix m1(2, 3, -1);
39     const Matrix m2(m1);
40     std::cout << "矩阵对象m1: \n"; m1.print();
41     std::cout << "矩阵对象m2: \n"; m2.print();
42     m1.clear();
43     m1.at(0, 0) = 1;
44     std::cout << "m1更新后: \n";
45     std::cout << "矩阵对象m1第0行 "; output(m1, 0);
46     std::cout << "矩阵对象m2第0行: "; output(m2, 0);
47 }
48  
49 // 输出矩阵对象row_index行所有元素
50 void output(const Matrix& m, int row_index) {
51     if (row_index < 0 || row_index > m.rows()) {
52         std::cerr << "IndexError: row index out of range\n";
53         std::exit(1);
54     }
55     std::cout << m.at(row_index, 0);
56     for (int j = 1; j < m.cols(); ++j)
57         std::cout << ", " << m.at(row_index, j);
58     std::cout << '\n';
59 }

##运行结果

image

 ##实验任务5

#代码

 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_) 
21     : name{name_}, phone{phone_} {
22 }
23 
24 const std::string& Contact::get_name() const {
25     return name;
26 }
27 
28 const std::string& Contact::get_phone() const {
29     return phone;
30 }
31 
32 void Contact::display() const {
33     std::cout << name << ", " << phone;
34 }
 1  # pragma  once
 2  #include <iostream>
 3  #include <string>
 4  #include <vector>
 5  #include <algorithm>
 6  #include "contact.hpp"
 7  // 通讯录类
 8 class ContactBook {
 9  public:
10  void add(const std::string &name, const std::string &phone); // 添加联系人
11 void remove(const std::string &name); // 移除联系人
12 void find(const std::string &name) const; // 查找联系人
13 void display() const; // 显示所有联系人
14 size_t size() const;
15  private:
16  int index(const std::string &name) const;  // 返回联系人在contacts内索引,如不存在,返
17 回-1
18  void sort(); // 按姓名字典序升序排序通讯录
19 private:
20  std::vector<Contact> contacts;
21  };
22  }
23  void ContactBook::add(const std::string &name, const std::string &phone) {
24  if(index(name) == -1) {
25  contacts.push_back(Contact(name, phone));
26  std::cout << name << " add successfully.\n";
27  sort();
28  return;
29  }
30  std::cout << name << " already exists. fail to add!\n"; 
31 void ContactBook::remove(const std::string &name) {
32  int i = index(name);
33  if(i == -1) {
34  std::cout << name << " not found, fail to remove!\n";
35  return;
36  }
37  contacts.erase(contacts.begin()+i);
38  std::cout << name << " remove successfully.\n";
39  }
40 task5.cpp
41  void ContactBook::find(const std::string &name) const {
42     int i = index(name);
43     if(i == -1) {
44         std::cout << name << " not found!\n";
45         return;
46     }
47     contacts[i].display(); 
48     std::cout << '\n';
49  }
50  void ContactBook::display() const {
51     for(auto &c: contacts) {
52         c.display(); 
53         std::cout << '\n';
54     }
55  }
56  size_t ContactBook::size() const {
57     return contacts.size();
58  }
59 int ContactBook::index(const std::string &name) const {
60     for (size_t i = 0; i < contacts.size(); ++i) {
61         if (contacts[i].get_name() == name) {
62             return static_cast<int>(i);
63         }
64     }
65     return -1;
66 }
67 void ContactBook::sort() {
68     std::sort(contacts.begin(), contacts.end(), 
69         [](const Contact &a, const Contact &b) {
70             return a.get_name() < b.get_name();
71         });
72 }
 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     return 0;
28 }

##运行结果

image

 

posted @ 2025-11-25 20:23  xzhls  阅读(0)  评论(0)    收藏  举报