实验3

实验任务1:

代码:

button.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <string>
 5 
 6 class Button {
 7 public:
 8     Button(const std::string &label_);
 9     const std::string& get_label() const;
10     void click();
11 
12 private:
13     std::string label;
14 };
15 
16 Button::Button(const std::string &label_): label{label_} {
17 }
18 
19 inline const std::string& Button::get_label() const {
20     return label;
21 }
22 
23 inline void Button::click() {
24     std::cout << "Button '" << label << "' clicked\n";
25 }

window.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <vector>
 5 #include <algorithm>
 6 #include "button.hpp"
 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 }

task1.cpp

 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 }

运行测试截图:

image

 回答问题:

问题1:是,window类中包含vector<Button>

问题2:(1)优点:外部代码可直接调用;风险:破坏了类的封装性

(2)若函数是用户需要直接调用,且不涉及内部实现细节,则设为public;若函数是实现细节,或调用它可能破坏对象状态的一致性,则设为private

问题3:接口1:仅返回已有字符串的引用,无内存拷贝,效率高:需注意对象生命周期;接口2:返回值,安全但可能有拷贝开销

问题4:emplace_back直接构造对象,避免临时对象拷贝,效率更高

 

实验任务2:

代码:

task2.cpp

 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 }

运行测试截图:

image

 回答问题:

问题1:std::vector<int> v1(5, 42):填充构造;const std::vector<int> v2(v1):拷贝构造;各包含5个

问题2:v1.size() = 2;v2.size() = 2;v1[0].size() = 3

问题3:效果相同。v1.at(0) = -1会做越界检查;v1[0]不会

问题4:(1)能。因为 r 是引用,指向 v1[0] 的末尾元素

(2)const &避免子 vector 的拷贝构造,直接引用原对象,但不能修改

问题5:(1)深复制

(2)当v是vector<int> 时,返回T&;当v是const vector<int> 时,返回const T&;必须

 

实验任务3:

代码:

vectorInt.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 
 5 class vectorInt{
 6 public:
 7     vectorInt();
 8     vectorInt(int n_);
 9     vectorInt(int n_, int value);
10     vectorInt(const vectorInt &vi);
11     ~vectorInt();
12     
13     int size() const;
14     int& at(int index);
15     const int& at(int index) const;
16     vectorInt& assign(const vectorInt &vi);
17 
18     int* begin();
19     int* end();
20     const int* begin() const;
21     const int* end() const;
22 
23 private:
24     int n;
25     int *ptr;
26 };
27 
28 vectorInt::vectorInt():n{0}, ptr{nullptr} {
29 }
30 
31 vectorInt::vectorInt(int n_): n{n_}, ptr{new int[n]} {
32 }
33 
34 vectorInt::vectorInt(int n_, int value): n{n_}, ptr{new int[n_]} {
35     for(auto i = 0; i < n; ++i)
36         ptr[i] = value;
37 }
38 
39 vectorInt::vectorInt(const vectorInt &vi): n{vi.n}, ptr{new int[n]} {
40     for(auto i = 0; i < n; ++i)
41         ptr[i] = vi.ptr[i];
42 }
43 
44 vectorInt::~vectorInt() {
45     delete [] ptr;
46 }
47 
48 int vectorInt::size() const {
49     return n;
50 }
51 
52 const int& vectorInt::at(int index) const {
53     if(index < 0 || index >= n) {
54         std::cerr << "IndexError: index out of range\n";
55         std::exit(1);
56     }
57 
58     return ptr[index];
59 }
60 
61 int& vectorInt::at(int index) {
62     if(index < 0 || index >= n) {
63         std::cerr << "IndexError: index out of range\n";
64         std::exit(1);
65     }
66 
67     return ptr[index];
68 }
69 
70 vectorInt& vectorInt::assign(const vectorInt &vi) { 
71     if(this == &vi) 
72         return *this;
73 
74     int *ptr_tmp;
75     ptr_tmp = new int[vi.n];
76     for(int i = 0; i < vi.n; ++i)
77         ptr_tmp[i] = vi.ptr[i];
78     
79     delete[] ptr;
80     n = vi.n;
81     ptr = ptr_tmp;
82     return *this;
83 }
84 
85 int* vectorInt::begin() {
86     return ptr;
87 }
88 
89 int* vectorInt::end() {
90     return ptr+n;
91 }
92 
93 const int* vectorInt::begin() const {
94     return ptr;
95 }
96 
97 const int* vectorInt::end() const {
98     return ptr+n;
99 }

task3.cpp

 1 #include "vectorInt.hpp"
 2 #include <iostream>
 3 
 4 void test1();
 5 void test2();
 6 void output1(const vectorInt &vi);
 7 void output2(const vectorInt &vi);
 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     int n;
19     std::cout << "Enter n: ";
20     std::cin >> n;
21 
22     vectorInt x1(n);
23     for(auto i = 0; i < n; ++i)
24         x1.at(i) = (i+1)*10;
25     std::cout << "x1: ";  output1(x1);
26 
27     vectorInt x2(n, 42);
28     vectorInt x3(x2);
29     x2.at(0) = -1;
30     std::cout << "x2: ";  output1(x2);
31     std::cout << "x3: ";  output1(x3);
32 }
33 
34 void test2() {
35     const vectorInt  x(5, 42);
36     vectorInt y;
37 
38     y.assign(x);
39 
40     std::cout << "x: ";  output2(x);
41     std::cout << "y: ";  output2(y);
42 }
43 
44 void output1(const vectorInt &vi) {
45     if(vi.size() == 0) {
46         std::cout << '\n';
47         return;
48     }
49         
50     std::cout << vi.at(0);
51     for(auto i = 1; i < vi.size(); ++i)
52         std::cout << ", " << vi.at(i);
53     std::cout << '\n';
54 }
55 
56 void output2(const vectorInt &vi) {
57     if(vi.size() == 0) {
58         std::cout << '\n';
59         return;
60     }
61     
62     auto it = vi.begin();
63     std::cout << *it;
64 
65     for(it = vi.begin()+1; it != vi.end(); ++it)
66         std::cout << ", " << *it;
67     std::cout << '\n';
68 }

运行测试截图:

image

 回答问题:

问题1:版本2问题:未处理自赋值,若this==&vi,delete[ ] ptr后访问vi.ptr会出错

问题2:(1)static_cast<const vectorInt*>(this)的作用:转换前this类型:vectorInt*;转换后this类型:const vectorInt*;转换目的:将当前非 const 对象的指针转换为 const 指针,调用const版本的at接口

(2)const_cast<int&>的作用:转换前返回类型:const int&;转换后返回类型:int&;转换目的:去除const版本at返回值的const属性,返回非 const 引用。

问题3:(1)v1.begin() 调用非 const 版本,v2.begin() 调用 const 版本

问题4:可行。fill_n 填充值,copy_n 复制数组

 

实验任务4:

代码:

matrix.cpp

 1 #include "matrix.hpp"
 2 #include <iostream>
 3 #include <cstddef>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 
 7 Matrix::Matrix(int rows_, int cols_, double value)
 8     : n_rows(rows_), n_cols(cols_), ptr(new double[rows_ * cols_]) {
 9     std::fill_n(ptr, rows_ * cols_, value);
10 }
11 
12 Matrix::Matrix(int rows_, double value)
13     : Matrix(rows_, rows_, value) {}
14 
15 Matrix::Matrix(const Matrix &x)
16     : n_rows(x.n_rows), n_cols(x.n_cols), ptr(new double[x.n_rows * x.n_cols]) {
17     std::copy(x.ptr, x.ptr + x.n_rows * x.n_cols, ptr);
18 }
19 
20 Matrix::~Matrix() {
21     delete[] ptr;
22 }
23 
24 void Matrix::set(const double *pvalue, int size) {
25     if (size != n_rows * n_cols) {
26         std::cerr << "SizeError: size mismatch\n";
27         std::exit(1);
28     }
29     std::copy(pvalue, pvalue + size, ptr);
30 }
31 
32 void Matrix::clear() {
33     std::fill_n(ptr, n_rows * n_cols, 0.0);
34 }
35 
36 const double& Matrix::at(int i, int j) const {
37     if (i < 0 || i >= n_rows || j < 0 || j >= n_cols) {
38         std::cerr << "IndexError: (i,j) out of range\n";
39         std::exit(1);
40     }
41     return ptr[i * n_cols + j];
42 }
43 
44 double& Matrix::at(int i, int j) {
45     return const_cast<double&>(
46         static_cast<const Matrix*>(this)->at(i, j)
47     );
48 }
49 
50 int Matrix::rows() const {
51     return n_rows;
52 }
53 
54 int Matrix::cols() const {
55     return n_cols;
56 }
57 
58 void Matrix::print() const {
59     for (int i = 0; i < n_rows; ++i) {
60         std::cout << ptr[i * n_cols];
61         for (int j = 1; j < n_cols; ++j) {
62             std::cout << ", " << ptr[i * n_cols + j];
63         }
64         std::cout << "\n";
65     }
66 }

matrix.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cstdlib>
 6 
 7 class Matrix {
 8 public:
 9     Matrix(int rows_, int cols_, double value = 0);
10     Matrix(int rows_, double value = 0);
11     Matrix(const Matrix &x); 
12     ~Matrix();
13 
14     void set(const double *pvalue, int size);
15     void clear();
16     
17     const double& at(int i, int j) const;
18     double& at(int i, int j);
19     
20     int rows() const;
21     int cols() const;
22 
23     void print() const;
24 
25 private:
26     int n_rows;
27     int n_cols;
28     double *ptr;
29 };

task4.cpp

 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);
25     m1.set(x, n*m);
26 
27     Matrix m2(m, n);
28     m2.set(x, m*n); 
29 
30     Matrix m3(n);
31     m3.set(x, n*n);
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 void output(const Matrix &m, int row_index) {
54     if(row_index < 0 || row_index >= m.rows()) {
55         std::cerr << "IndexError: row index out of range\n";
56         exit(1);
57     }
58 
59     std::cout << m.at(row_index, 0);
60     for(int j = 1; j < m.cols(); ++j)
61         std::cout << ", " << m.at(row_index, j);
62     std::cout << '\n';
63 }

运行测试截图:

image

 实验任务5:

代码:

contact.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <string>
 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 }

 

contactBook.hpp

 1 # pragma  once
 2 
 3 #include <iostream>
 4 #include <string>
 5 #include <vector>
 6 #include <algorithm>
 7 #include "contact.hpp"
 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; 
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 int ContactBook::index(const std::string &name) const {
72     for (size_t i = 0; i < contacts.size(); ++i) {
73         if (contacts[i].get_name() == name) { 
74             return static_cast<int>(i);
75         }
76     }
77     return -1;
78 }
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     );
86 }

 

task5.cpp

 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 }

 

运行测试截图:

image

 

posted @ 2025-11-26 01:21  雅ya  阅读(1)  评论(0)    收藏  举报