实验三

任务一

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

屏幕截图 2025-11-24 234648

问题一:是

问题二:1、可外部调用,破坏了封装,有数据泄露风险

    2、公有(用户需要,不易损坏内部数据),私有(仅内部使用,有敏感数据)

问题三:接口一避免了数据的复制,接口二没有

问题四:是,在大多数情况下,emplace_back() 提供了更好的性能,特别是在构造代价较高的对象时。但在添加已有对象或需要明确表达意图时,push_back() 仍然是合适的选择。

 任务二:
 1 #include <iostream>
 2 #include <vector>
 3 void test1();
 4 void test2();
 5 void output1(const std::vector<int>& v);
 6 void output2(const std::vector<int>& v);
 7 void output3(const std::vector<std::vector<int>>& v);
 8 int main() {
 9     std::cout << "深复制验证1: 标准库vector<int>\n";
10     test1();
11     std::cout << "\n深复制验证2: 标准库vector<int>嵌套使用\n";
12     test2();
13 }
14 void test1() {
15     std::vector<int> v1(5, 42);
16     const std::vector<int> v2(v1);
17 
18     std::cout << "**********拷贝构造后**********\n";
19     std::cout << "v1: "; output1(v1);
20     std::cout << "v2: "; output1(v2);
21     
22     v1.at(0) = -1;
23     
24     std::cout << "**********修改v1[0]后**********\n";
25     std::cout << "v1: "; output1(v1);
26     std::cout << "v2: "; output1(v2);
27 
28 }
29 void test2() {
30     std::vector<std::vector<int>> v1{ {1, 2, 3}, {4, 5, 6, 7} };
31     const std::vector<std::vector<int>> v2(v1);
32     std::cout << "**********拷贝构造后**********\n";
33     std::cout << "v1: "; output3(v1);
34     std::cout << "v2: "; output3(v2);
35     v1.at(0).push_back(-1);
36     std::cout << "**********修改v1[0]后**********\n";
37     std::cout << "v1: \n";  output3(v1);
38     std::cout << "v2: \n";  output3(v2);
39 }
40 // 使用xx.at()+循环输出vector<int>数据项
41 void output1(const std::vector<int>& v) {
42     if (v.size() == 0) {
43         std::cout << '\n';
44         return;
45     }
46     std::cout << v.at(0);
47     for (auto i = 1; i < v.size(); ++i)
48         std::cout << ", " << v.at(i);
49     std::cout << '\n';
50 }
51 // 使用迭代器+循环输出vector<int>数据项
52 void output2(const std::vector<int>& v) {
53     if (v.size() == 0) {
54         std::cout << '\n';
55         return;
56     }
57     auto it = v.begin();
58     std::cout << *it;
59     for (it = v.begin() + 1; it != v.end(); ++it)
60         std::cout << ", " << *it;
61     std::cout << '\n';
62 }
63 // 使用auto for分行输出vector<vector<int>>数据项
64 void output3(const std::vector<std::vector<int>>& v) {
65     if (v.size() == 0) {
66         std::cout << '\n';
67         return;
68     }
69     for (auto& i : v)
70         output2(i);
71 }

屏幕截图 2025-11-24 234933

问题一:普通参数构造、拷贝构造;都是5个

问题二:2、2、3

问题三:能,at有边界检查

问题四:1、能,v1.at(0)中末尾加入了-1

    2、不占多余空间,不能修改

问题五:1、深复制

    2、int&,const int&,是

任务三:

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

屏幕截图 2025-11-25 212356

问题一:主要差异在于内存管理和异常安全方面,

  ptr = new int[n];如果这里new抛出异常,对象将处于无效状态

   v.assign(v); 自赋值:版本2会先删除自己的内存,然后访问已删除的数据
问题二:
  1、将当前对象的指针转化为常量指针,转换前是vectorInt* const this,转换后是
const vectorInt* this,转换目的是调用常量成员函数,避免代码重复,实现成对函数,
在常量上下文中使用
  2、移除引用类型的常量性,转换前是const int&,转换后是int&,目的是实现常
量重载模式、修改mutable成员变量、兼容遗留代码
问题三:
  非const,const
问题四:
  可以
    std::fill_n(ptr, n, value):将ptr开始的n个元素都设置为value
    std::copy_n(v1.ptr, v1.n, ptr):从v1.ptr复制v1.n个元素到ptr
    std::copy_n(v1.ptr, v1.n, ptr_tmp):从v1.ptr复制v1.n个元素到临时缓冲区ptr_tmp
任务四:
 1 #pragma once
 2 // 类Matrix声明
 3 class Matrix {
 4 public:
 5     Matrix(int rows_, int cols_, double value = 0); // 构造rows_*cols_矩阵对象, 初值value
 6     Matrix(int rows_, double value = 0);
 7     // 构造rows_*rows_方阵对象, 初值value
 8     Matrix(const Matrix& x);
 9     ~Matrix();
10     void set(const double* pvalue, int size);   // 按行复制pvalue指向的数据,要求size = rows * cols, 否则报错退出
11     void clear();   // 矩阵对象数据项置0
12     const double& at(int i, int j) const;   // 返回矩阵对象索引(i,j)对应的数据项const引用(越界则报错后退出)
13     double& at(int i, int j);   // 返回矩阵对象索引(i,j)对应的数据项引用(越界则报错后退出)
14     int rows() const;   // 返回矩阵对象行数
15     int cols() const;   // 返回矩阵对象列数
16     void print() const;   // 按行打印数据
17 private:
18     int n_rows;
19     int n_cols;
20     double* ptr;
21 };
 1 #include<iostream>
 2 #include"matrix.hpp";
 3 
 4 Matrix::Matrix(int rows_, int cols_, double value) :n_rows{ rows_ }, n_cols{ cols_ } {
 5     if (rows_ <= 0 || cols_ <= 0) {
 6         throw std::invalid_argument("矩阵的行数、列数应为正整数");
 7     }
 8     ptr = new double[n_rows * n_cols];
 9     for (int i = 0; i < n_cols * n_rows; i++) {
10         ptr[i] = value;
11     }
12 }
13 Matrix::Matrix(int rows_, double value) :n_rows{ rows_ }, n_cols{ rows_ } {
14     if (rows_ <= 0) {
15         throw std::invalid_argument("矩阵的行数、列数应为正整数");
16     }
17     ptr = new double[n_rows * n_cols];
18     for (int i = 0; i < n_cols * n_rows; i++) {
19         ptr[i] = value;
20     }
21 }
22 Matrix::Matrix(const Matrix& x) :n_rows{ x.n_rows }, n_cols{ x.n_cols } {
23     ptr = new double[n_cols * n_rows];
24     std::memcpy(ptr, x.ptr, n_rows * n_cols * sizeof(double));
25 }
26 
27 Matrix::~Matrix() {};
28 
29 void Matrix::set(const double* pvalue, int size) {
30     if (n_cols * n_rows != size) {
31         throw std::invalid_argument("请检查Size大小");
32     }
33     std::memcpy(ptr, pvalue, size * sizeof(double));
34 }
35 
36 void Matrix::clear() {
37     for (int i = 0; i < n_rows * n_cols; i++) {
38         ptr[i] = 0.0;
39     }
40 }
41 
42 const double& Matrix::at(int i, int j)const {
43     if (i < 0 || i >= n_rows || j < 0 || j >= n_cols) {
44         throw std::out_of_range("访问越界,访问失败");
45     }
46     return ptr[i * n_cols + j];
47 }
48 
49 double& Matrix::at(int i, int j) {
50     if (i < 0 || i >= n_rows || j < 0 || j >= n_cols) {
51         throw std::out_of_range("访问越界,访问失败");
52     }
53     return ptr[i * n_cols + j];
54 }
55 
56 int Matrix::rows()const {
57     return n_rows;
58 }
59 
60 int Matrix::cols()const {
61     return n_cols;
62 }
63 
64 void Matrix::print()const {
65     for (int i = 0; i < n_rows; i++) {
66         for (int j = 0; j < n_cols; j++) {
67             std::cout << at(i, j) << " ";
68         }
69         std::cout << std::endl;
70     }
71     std::cout << std::endl;
72 }
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include "matrix.hpp"
 4 // 矩阵对象内元素行数
 5 // 矩阵对象内元素列数
 6 // 数据区
 7 void test1();
 8 void test2();
 9 void output(const Matrix& m, int row_index);
10 int main() {
11     std::cout << "测试1: \n";
12     test1();
13 
14     std::cout << "\n测试2: \n";
15     test2();
16 }
17 
18 void test1() {
19     double x[1000] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
20     int n, m;
21     std::cout << "Enter n and m: ";
22     std::cin >> n >> m;
23     Matrix m1(n, m);
24     m1.set(x, n * m);
25     Matrix m2(m, n);
26     m2.set(x, m * n);
27     Matrix m3(n);
28     m3.set(x, n * n);
29     // 创建矩阵对象m1, 大小n×m
30      // 用一维数组x的值按行为矩阵m1赋值
31     // 创建矩阵对象m2, 大小m×n
32      // 用一维数组x的值按行为矩阵m1赋值
33     // 创建一个n×n方阵对象
34     // 用一维数组x的值按行为矩阵m3赋值
35     std::cout << "矩阵对象m1: \n";   m1.print();
36     std::cout << "矩阵对象m2: \n";   m2.print();
37     std::cout << "矩阵对象m3: \n";   m3.print();
38 }
39 void test2() {
40     Matrix m1(2, 3, -1);
41     const Matrix m2(m1);
42     std::cout << "矩阵对象m1: \n";   m1.print();
43     std::cout << "矩阵对象m2: \n";   m2.print();
44     m1.clear();
45     m1.at(0, 0) = 1;
46     std::cout << "m1更新后: \n";
47     std::cout << "矩阵对象m1第0行 "; output(m1, 0);
48     std::cout << "矩阵对象m2第0行: "; output(m2, 0);
49 }
50 // 输出矩阵对象row_index行所有元素
51 void output(const Matrix& m, int row_index) {
52     if (row_index < 0 || row_index > m.rows()) {
53         std::cerr << "IndexError: row index out of range\n";
54         std::exit(1);
55     }
56     std::cout << m.at(row_index, 0);
57     for (int j = 1; j < m.cols(); ++j)
58         std::cout << ", " << m.at(row_index, j);
59     std::cout << '\n';
60 }

屏幕截图 2025-11-25 200526

任务五:

 1 #include <iostream>
 2 #include <string>
 3 // 联系人类
 4 class Contact {
 5 public:
 6     Contact(const std::string& name_, const std::string& phone_);
 7     const std::string& get_name() const;
 8     const std::string& get_phone() const;
 9     void display() const;
10 private:
11     std::string name;
12     // 必填项
13     std::string phone;   // 必填项
14 };
15 Contact::Contact(const std::string& name_, const std::string& phone_) :name{ name_ },
16 phone{ phone_ } {
17 }
18 const std::string& Contact::get_name() const {
19     return name;
20 }
21 const std::string& Contact::get_phone() const {
22     return phone;
23 }
24 void Contact::display() const {
25     std::cout << name << ", " << phone;
26 }
 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内索引,如不存在,返回 - 1
17     void sort(); // 按姓名字典序升序排序通讯录
18 private:
19     std::vector<Contact> contacts;
20 };
21  
22 void ContactBook::add(const std::string& name, const std::string& phone) {
23     if (index(name) == -1) {
24         contacts.push_back(Contact(name, phone));
25         std::cout << name << " add successfully.\n";
26         sort();
27         return;
28     }
29     std::cout << name << " already exists. fail to add!\n";
30 }
31 
32 void ContactBook::remove(const std::string& name) {
33     int i = index(name);
34     if (i == -1) {
35         std::cout << name << " not found, fail to remove!\n";
36         return;
37     }
38     contacts.erase(contacts.begin() + i);
39     std::cout << name << " remove successfully.\n";
40 }
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      // 待补足1:int index(const std::string &name) const;实现
60     // 返回联系人在contacts内索引; 如不存在,返回-1
61 int ContactBook::index(const std::string& name) const {
62     for (const auto &i : contacts) {
63         if (i.get_name() == name) {
64             return 1;
65         }
66     }
67     return -1;
68 }
69      // 待补足2:void ContactBook::sort() 按姓名字典序升序排序通讯录
70 void ContactBook::sort() {
71     std::sort(contacts.begin(), contacts.end(), [](const Contact& a, const Contact& b) {
72         return a.get_name() < b.get_name();
73         });
74 }
 1 #include "contactBook.hpp"
 2 #include<iostream>
 3 void test() {
 4     ContactBook contactbook;
 5     std::cout << "1. add contacts\n";
 6     contactbook.add("Bob", "18199357253");
 7     contactbook.add("Alice", "17300886371");
 8     contactbook.add("Linda", "18184538072");
 9     contactbook.add("Alice", "17300886371");
10     std::cout << "\n2. display contacts\n";
11     std::cout << "There are " << contactbook.size() << " contacts.\n";
12     contactbook.display();
13     std::cout << "\n3. find contacts\n";
14     contactbook.find("Bob");
15     contactbook.find("David");
16     std::cout << "\n4. remove contact\n";
17     contactbook.remove("Bob");
18     contactbook.remove("David");
19 }
20 int main() {
21     test();
22 }

屏幕截图 2025-11-25 214922

 

posted @ 2025-11-25 21:49  Little_Zcy  阅读(0)  评论(0)    收藏  举报