实验3

Task1

(1)

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

(2)运行结果

image

 (3)回答问题

① 是组合关系。因为在Window类中std::vector<Button>buttons;

②a.优点:方便调用。

缺点:容易泄露。

b.看用户需求。需要直接调用的用public,需要防止数据的泄露用private。

③接口一比接口二的性能好,效率高,但接口二比接口一安全性好。

④可以正常运行,原来的写法是先构造一个临时Button对象,再将其拷贝到vector中,而改写的写法是直接在vector的内存空间中构造Button对象,省去了临时对象的创建和拷贝过程。

task2

(1)

 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  v1.at(0) = -1;
18  std::cout << "**********拷贝构造后**********\n";
19  std::cout << "v1: "; output1(v1);
20  std::cout << "v2: "; output1(v2);
21  std::cout << "**********修改v1[0]后**********\n";
22  std::cout << "v1: "; output1(v1);
23  std::cout << "v2: "; output1(v2); 
24 }
25 void test2() {
26 std::vector<std::vector<int>> v1{{1, 2, 3}, {4, 5, 6, 7}};
27  const std::vector<std::vector<int>> v2(v1);
28  std::cout << "**********拷贝构造后**********\n";
29  std::cout << "v1: "; output3(v1);
30  std::cout << "v2: "; output3(v2);
31  v1.at(0).push_back(-1);
32  std::cout << "**********修改v1[0]后**********\n";
33  std::cout << "v1: \n";  output3(v1);
34  std::cout << "v2: \n";  output3(v2);
35 } 
36  // 使用xx.at()+循环输出vector<int>数据项
37 void output1(const std::vector<int> &v) {
38  if(v.size() == 0) {
39  std::cout << '\n';
40  return;
41  }
42  std::cout << v.at(0);
43  for(auto i = 1; i < v.size(); ++i)
44  std::cout << ", " << v.at(i);
45  std::cout << '\n';  
46 }
47  // 使用迭代器+循环输出vector<int>数据项
48 void output2(const std::vector<int> &v) {
49  if(v.size() == 0) {
50  std::cout << '\n';
51  return;
52  }
53  auto it = v.begin();
54  std::cout << *it;
55  for(it = v.begin()+1; it != v.end(); ++it)
56  std::cout << ", " << *it;
57  std::cout << '\n';
58  }
59  // 使用auto for分行输出vector<vector<int>>数据项
60 void output3(const std::vector<std::vector<int>>& v) {
61  if(v.size() == 0) {
62  std::cout << '\n';
63  return;
64  }
65  for(auto &i: v)
66  output2(i);
67 }
task.cpp

 

(2)运行结果

image

 (3)回答问题

①第一行构造了一个包含5个元素的vector,每个元素值为42。第二行是用v1的内容创建一个新的vector v2。v1包含5个值为42的数据项,v2也有5个。

②v1.size()是2,v2.size()是2,v3.size()是3。

③可以实现同等效果,v1.at()=-1越界会报错,v1[0]=-1越界可能崩溃或数据错误。

④a.可以输出-1。

b.优势:数据的安全性强。劣势:只能读取,不能修改。

⑤a.是深复制。

    b.返回值分别为int类型、const int&类型。必须提供带const修饰的重载版本。

task3

(1)

 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 }
vectorInt.hpp
 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      std::cout << "x: ";  output2(x);
32      std::cout << "y: ";  output2(y);
33 }
34  // 使用xx.at()+循环输出vectorInt对象数据项
35 void output1(const vectorInt &vi) {
36  if(vi.size() == 0) {
37  std::cout << '\n';
38  return;
39  }
40  std::cout << vi.at(0);
41   for(auto i = 1; i < vi.size(); ++i)
42  std::cout << ", " << vi.at(i);
43  std::cout << '\n';
44  }
45  // 使用迭代器+循环输出vectorInt对象数据项
46 void output2(const vectorInt &vi) {
47  if(vi.size() == 0) {
48  std::cout << '\n';
49  return;
50  }
51  auto it = vi.begin();
52  std::cout << *it;
53  for(it = vi.begin()+1; it != vi.end(); ++it)
54  std::cout << ", " << *it;
55  std::cout << '\n';
56 }
task.cpp

(2)运行结果

image

 (3)回答问题

①缺少返回值。

②a.static_cast<const vectorInt*>(this)的作用是将非const指针转换为const指针。

        转换前this的类型是非const指针,转换后是const指针。

  转换目的:保护数据。

     b. const_cast<int&>的作用是将const引用转换为非const引用。

  转换前的返回值类型为const int&,转换后为int&。

  转换目的:使返回值可以修改。

③v1是非const版本,而v2是const版本。

  第一个版本是要修改元素时使用,第二个版本是保护数据时使用。

④可行。第一行代码的功能是填充数组。

  第二行代码的功能是复制数据到新对象。

  第三行代码的功能是安全替换当前对象的数据。

task4

(1)

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

(2)运行结果

image

 task5

(1)

 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     const std::string &get_name() const;
10     const std::string &get_phone() const;
11     void display() const;
12     
13 private:
14     std::string name; // 必填项
15     std::string phone; // 必填项
16 };
17 
18 Contact::Contact(const std::string &name_, const std::string &phone_)
19     : 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 }
contact.hpp
 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 public:
12     void add(const std::string &name, const std::string &phone); // 添加联系人
13     void remove(const std::string &name); // 移除联系人
14     void find(const std::string &name) const; // 查找联系人
15     void display() const; // 显示所有联系人
16     size_t size() const;
17 
18 private:
19     int index(const std::string &name) const; // 返回联系人在contacts内索引,如不存在,返回-1
20     void sort(); // 按姓名字典序升序排序通讯录
21 
22 private:
23     std::vector<Contact> contacts;
24 };
25 
26 void ContactBook::add(const std::string &name, const std::string &phone) {
27     if(index(name) == -1) {
28         contacts.push_back(Contact(name, phone));
29         std::cout << name << " add successfully.\n";
30         sort();
31         return;
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     if(i == -1) {
39         std::cout << name << " not found, fail to remove!\n";
40         return;
41     }
42     contacts.erase(contacts.begin() + i);
43     std::cout << name << " remove successfully.\n";
44 }
45 
46 void ContactBook::find(const std::string &name) const {
47     int i = index(name);
48     if(i == -1) {
49         std::cout << name << " not found!\n";
50         return;
51     }
52     contacts[i].display();
53     std::cout << '\n';
54 }
55 
56 void ContactBook::display() const {
57     for(auto &c: contacts) {
58         c.display();
59         std::cout << '\n';
60     }
61 }
62 
63 size_t ContactBook::size() const {
64     return contacts.size();
65 }
66 
67 // 待补足1: int index(const std::string &name) const; 实现
68 // 返回联系人在contacts内索引;如不存在,返回-1
69 int ContactBook::index(const std::string &name) const {
70     for (size_t i = 0; i < contacts.size(); ++i) {
71         if (contacts[i].get_name() == name) {
72             return static_cast<int>(i);
73         }
74     }
75     return -1;
76 }
77 
78 // 待补足2: void ContactBook::sort(); 实现
79 // 按姓名字典序升序排序通讯录
80 void ContactBook::sort() {
81     std::sort(contacts.begin(), contacts.end(), 
82         [](const Contact &a, const Contact &b) {
83             return a.get_name() < b.get_name();
84         });
85 }
contactBook.hpp
 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 }
task.cpp

(2)运行结果

image

 

posted @ 2025-11-26 00:40  deep_l  阅读(5)  评论(1)    收藏  举报