任务1.
button.hpp
#pragma once#include <iostream> #include <string>class Button { public:Button(const std::string &label_);const std::string& get_label() const;void click();private:std::string label; };Button::Button(const std::string &label_): label{label_} { }inline const std::string& Button::get_label() const {return label; }inline void Button::click() {std::cout << "Button '" << label << "' clicked\n"; }
window.hpp
#pragma once#include <iostream> #include <vector> #include <algorithm> #include "button.hpp"// 窗口类 class Window{ public:Window(const std::string &title_);void display() const;void close();void add_button(const std::string &label);void click_button(const std::string &label);private:bool has_button(const std::string &label) const;private:std::string title;std::vector<Button> buttons; };Window::Window(const std::string &title_): title{title_} {buttons.push_back(Button("close")); }inline void Window::display() const {std::string s(40, '*');std::cout << s << std::endl;std::cout << "window : " << title << std::endl;int cnt = 0;for(const auto &button: buttons)std::cout << ++cnt << ". " << button.get_label() << std::endl;std::cout << s << std::endl; }inline void Window::close() {std::cout << "close window '" << title << "'" << std::endl;click_button("close"); }inline bool Window::has_button(const std::string &label) const {for(const auto &button: buttons)if(button.get_label() == label)return true;return false; }inline void Window::add_button(const std::string &label) {if(has_button(label))std::cout << "button " << label << " already exists!\n";elsebuttons.push_back(Button(label)); }inline void Window::click_button(const std::string &label) {for(auto &button:buttons)if(button.get_label() == label) {button.click();return;}std::cout << "no button: " << label << std::endl; }
task1.cpp
#include "window.hpp" #include <iostream>void test(){Window w("Demo");w.add_button("add");w.add_button("remove");w.add_button("modify");w.add_button("add");w.display();w.close(); }int main() {std::cout << "用组合类模拟简单GUI:\n";test(); }
运行结果如图:

问题1:是组合关系
问题2:(1)优点:外部可以查询按钮是否存在,增加灵活性 缺点:暴露了内部实现细节,破坏了封装性
(2)1.用户是否需要:用户直接需要的功能设为public,仅为内部服务设为private
2.对象状态安全:可能破坏对象一致性的操作应设为private
问题3:接口一:返回引用,避免拷贝,性能更好;调用者可能保存引用并意外修改原始数据
接口二:返回值拷贝,性能较差,特别是字符串较长时;完全安全,调用者获得的是副本,不会影响原始对象
接口1更好,Button的label通常不会很大,性能优势明显
问题4:修改为emplace_back后程序功能不变,但性能更优。
任务2.
task2.cpp
#include <iostream> #include <vector>void test1(); void test2(); void output1(const std::vector<int> &v); void output2(const std::vector<int> &v); void output3(const std::vector<std::vector<int>>& v);int main() {std::cout << "深复制验证1: 标准库vector<int>\n";test1();std::cout << "\n深复制验证2: 标准库vector<int>嵌套使用\n";test2(); }void test1() {std::vector<int> v1(5, 42);const std::vector<int> v2(v1);std::cout << "**********拷贝构造后**********\n";std::cout << "v1: "; output1(v1);std::cout << "v2: "; output1(v2);v1.at(0) = -1;std::cout << "**********修改v1[0]后**********\n";std::cout << "v1: "; output1(v1);std::cout << "v2: "; output1(v2); }void test2() {std::vector<std::vector<int>> v1{{1, 2, 3}, {4, 5, 6, 7}};const std::vector<std::vector<int>> v2(v1);std::cout << "**********拷贝构造后**********\n";std::cout << "v1: "; output3(v1);std::cout << "v2: "; output3(v2);v1.at(0).push_back(-1);std::cout << "**********修改v1[0]后**********\n";std::cout << "v1: \n"; output3(v1);std::cout << "v2: \n"; output3(v2); }// 使用xx.at()+循环输出vector<int>数据项 void output1(const std::vector<int> &v) {if(v.size() == 0) {std::cout << '\n';return;}std::cout << v.at(0);for(auto i = 1; i < v.size(); ++i)std::cout << ", " << v.at(i);std::cout << '\n'; }// 使用迭代器+循环输出vector<int>数据项 void output2(const std::vector<int> &v) {if(v.size() == 0) {std::cout << '\n';return;}auto it = v.begin();std::cout << *it;for(it = v.begin()+1; it != v.end(); ++it)std::cout << ", " << *it;std::cout << '\n'; }// 使用auto for分行输出vector<vector<int>>数据项 void output3(const std::vector<std::vector<int>>& v) {if(v.size() == 0) {std::cout << '\n';return;}for(auto &i: v)output2(i); }
运行结果如图:

问题1:v1包含5个值为42的数据项;v2包含5个值为42的数据项
问题2:v1.size() = 2 v2.size() = 2 v1[0].size() = 3
问题3:能
安全性:at()更安全;性能:operator[]稍快
问题4:
(1)能。v1.at(0)返回第一个内层vector的引用,r是该vector的引用,r.at(r.size()-1)访问最后一个元素,即刚push_back的-1
(2)优势:避免拷贝,节省内存,提高性能
限制:不能通过const引用修改所引用的对象
问题5:
(1)深复制
(2)当v是vector<int>时:v.at(0)返回int&,当v是const vector<int>时:v.at(0)返回const int&,at()必须提供const重载版本
任务3
vectorlnt.hpp
#pragma once#include <iostream>// 动态int数组对象类 class vectorInt{ public:vectorInt();vectorInt(int n_);vectorInt(int n_, int value);vectorInt(const vectorInt &vi);~vectorInt();int size() const;int& at(int index);const int& at(int index) const;vectorInt& assign(const vectorInt &vi);int* begin();int* end();const int* begin() const;const int* end() const;private:int n; // 当前数据项个数int *ptr; // 数据区 };vectorInt::vectorInt():n{0}, ptr{nullptr} { }vectorInt::vectorInt(int n_): n{n_}, ptr{new int[n]} { }vectorInt::vectorInt(int n_, int value): n{n_}, ptr{new int[n_]} {for(auto i = 0; i < n; ++i)ptr[i] = value; }vectorInt::vectorInt(const vectorInt &vi): n{vi.n}, ptr{new int[n]} {for(auto i = 0; i < n; ++i)ptr[i] = vi.ptr[i]; }vectorInt::~vectorInt() {delete [] ptr; }int vectorInt::size() const {return n; }const int& vectorInt::at(int index) const {if(index < 0 || index >= n) {std::cerr << "IndexError: index out of range\n";std::exit(1);}return ptr[index]; }int& vectorInt::at(int index) {if(index < 0 || index >= n) {std::cerr << "IndexError: index out of range\n";std::exit(1);}return ptr[index]; }vectorInt& vectorInt::assign(const vectorInt &vi) { if(this == &vi) return *this;int *ptr_tmp;ptr_tmp = new int[vi.n];for(int i = 0; i < vi.n; ++i)ptr_tmp[i] = vi.ptr[i];delete[] ptr;n = vi.n;ptr = ptr_tmp;return *this; }int* vectorInt::begin() {return ptr; }int* vectorInt::end() {return ptr+n; }const int* vectorInt::begin() const {return ptr; }const int* vectorInt::end() const {return ptr+n; }
task3.cpp
#include "vectorInt.hpp" #include <iostream>void test1(); void test2(); void output1(const vectorInt &vi); void output2(const vectorInt &vi);int main() {std::cout << "测试1: \n";test1();std::cout << "\n测试2: \n";test2(); }void test1() {int n;std::cout << "Enter n: ";std::cin >> n;vectorInt x1(n);for(auto i = 0; i < n; ++i)x1.at(i) = (i+1)*10;std::cout << "x1: "; output1(x1);vectorInt x2(n, 42);vectorInt x3(x2);x2.at(0) = -1;std::cout << "x2: "; output1(x2);std::cout << "x3: "; output1(x3); }void test2() {const vectorInt x(5, 42);vectorInt y;y.assign(x);std::cout << "x: "; output2(x);std::cout << "y: "; output2(y); }// 使用xx.at()+循环输出vectorInt对象数据项 void output1(const vectorInt &vi) {if(vi.size() == 0) {std::cout << '\n';return;}std::cout << vi.at(0);for(auto i = 1; i < vi.size(); ++i)std::cout << ", " << vi.at(i);std::cout << '\n'; }// 使用迭代器+循环输出vectorInt对象数据项 void output2(const vectorInt &vi) {if(vi.size() == 0) {std::cout << '\n';return;}auto it = vi.begin();std::cout << *it;for(it = vi.begin()+1; it != vi.end(); ++it)std::cout << ", " << *it;std::cout << '\n'; }
运行结果如下:

问题1:1.自赋值问题:没有检查 this == &vi,如果自赋值会导致访问已释放的内存
2.内存泄漏风险:如果new抛出异常,原ptr已被删除但新ptr未赋值
问题2:(1)转换前:vectorInt*(非const指针)
转换后:const vectorInt*(const指针)
将当前对象转换为const版本,以便调用const版本的at()方法
(2)转换前:const int&
转换后:const vectorInt*
将当前对象转换为const版本,以便调用const版本的at()方法
问题3:(1)非const版本:用于需要修改容器内容的场景 const版本:用于只读访问或const对象的场景
(2)vectorInt直接返回原始指针作为迭代器,说明迭代器本质上是提供统一访问接口的抽象
问题4:std::fill_n(ptr, n, value):从ptr开始,填充n个元素,每个元素值为value
std::copy_n(vi.ptr, vi.n, ptr):从vi.ptr复制vi.n个元素到ptr
std::copy_n(vi.ptr, vi.n, ptr_tmp):从vi.ptr复制vi.n个元素到ptr_tmp
可以
任务4:
matrix.hpp
#pragma once#include <iostream> #include <algorithm> #include <cstdlib>// 类Matrix声明 class Matrix { public:Matrix(int rows_, int cols_, double value = 0); // 构造rows_*cols_矩阵对象, 初值valueMatrix(int rows_, double value = 0); // 构造rows_*rows_方阵对象, 初值valueMatrix(const Matrix &x); // 深复制~Matrix();void set(const double *pvalue, int size); // 按行复制pvalue指向的数据,要求size=rows*cols,否则报错退出void clear(); // 矩阵对象数据项置0const double& at(int i, int j) const; // 返回矩阵对象索引(i,j)对应的数据项const引用(越界则报错后退出)double& at(int i, int j); // 返回矩阵对象索引(i,j)对应的数据项引用(越界则报错后退出)int rows() const; // 返回矩阵对象行数int cols() const; // 返回矩阵对象列数void print() const; // 按行打印数据private:int n_rows; // 矩阵对象内元素行数int n_cols; // 矩阵对象内元素列数double *ptr; // 数据区 };
task4.cpp
#include <iostream> #include <cstdlib> #include "matrix.hpp"void test1(); void test2(); void output(const Matrix &m, int row_index);int main() {std::cout << "测试1: \n";test1();std::cout << "\n测试2: \n";test2(); }void test1() {double x[1000] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int n, m;std::cout << "Enter n and m: ";std::cin >> n >> m;Matrix m1(n, m); // 创建矩阵对象m1, 大小n×mm1.set(x, n*m); // 用一维数组x的值按行为矩阵m1赋值 Matrix m2(m, n); // 创建矩阵对象m2, 大小m×nm2.set(x, m*n); // 用一维数组x的值按行为矩阵m1赋值 Matrix m3(n); // 创建一个n×n方阵对象m3.set(x, n*n); // 用一维数组x的值按行为矩阵m3赋值 std::cout << "矩阵对象m1: \n"; m1.print();std::cout << "矩阵对象m2: \n"; m2.print();std::cout << "矩阵对象m3: \n"; m3.print(); }void test2() {Matrix m1(2, 3, -1);const Matrix m2(m1);std::cout << "矩阵对象m1: \n"; m1.print();std::cout << "矩阵对象m2: \n"; m2.print();m1.clear();m1.at(0, 0) = 1;std::cout << "m1更新后: \n";std::cout << "矩阵对象m1第0行 "; output(m1, 0);std::cout << "矩阵对象m2第0行: "; output(m2, 0); }// 输出矩阵对象row_index行所有元素 void output(const Matrix &m, int row_index) {if(row_index < 0 || row_index >= m.rows()) {std::cerr << "IndexError: row index out of range\n";exit(1);}std::cout << m.at(row_index, 0);for(int j = 1; j < m.cols(); ++j)std::cout << ", " << m.at(row_index, j);std::cout << '\n'; }
运行结果如图:

任务5
contact.hpp
#pragma once#include <iostream> #include <string>// 联系人类 class Contact { public:Contact(const std::string &name_, const std::string &phone_);const std::string &get_name() const;const std::string &get_phone() const;void display() const;private:std::string name; // 必填项std::string phone; // 必填项 };Contact::Contact(const std::string &name_, const std::string &phone_) : name{name_}, phone{phone_} { }const std::string& Contact::get_name() const {return name; }const std::string& Contact::get_phone() const {return phone; }void Contact::display() const {std::cout << name << ", " << phone; }
contactBook.hpp
#pragma once#include <iostream> #include <string> #include <vector> #include <algorithm> #include "contact.hpp"// 通讯录类 class ContactBook { public:void add(const std::string &name, const std::string &phone); // 添加联系人void remove(const std::string &name); // 移除联系人void find(const std::string &name) const; // 查找联系人void display() const; // 显示所有联系人size_t size() const;private:int index(const std::string &name) const; // 返回联系人在contacts内索引,如不存在,返回-1void sort(); // 按姓名字典序升序排序通讯录private:std::vector<Contact> contacts; };void ContactBook::add(const std::string &name, const std::string &phone) {if(index(name) == -1) {contacts.push_back(Contact(name, phone));std::cout << name << " add successfully.\n";sort();return;}std::cout << name << " already exists. fail to add!\n"; }void ContactBook::remove(const std::string &name) {int i = index(name);if(i == -1) {std::cout << name << " not found, fail to remove!\n";return;}contacts.erase(contacts.begin() + i);std::cout << name << " remove successfully.\n"; }void ContactBook::find(const std::string &name) const {int i = index(name);if(i == -1) {std::cout << name << " not found!\n";return;}contacts[i].display();std::cout << '\n'; }void ContactBook::display() const {for(auto &c : contacts) {c.display();std::cout << '\n';} }size_t ContactBook::size() const {return contacts.size(); }// 待补足1: int index(const std::string &name) const; 实现 // 返回联系人在contacts内索引;如不存在,返回-1 int ContactBook::index(const std::string &name) const {for (size_t i = 0; i < contacts.size(); ++i) {if (contacts[i].get_name() == name) {return static_cast<int>(i);}}return -1; }// 待补足2: void ContactBook::sort(); 实现 // 按姓名字典序升序排序通讯录 void ContactBook::sort() {std::sort(contacts.begin(), contacts.end(), [](const Contact &a, const Contact &b) {return a.get_name() < b.get_name();}); }
task5.cpp
#include "contactBook.hpp"void test() {ContactBook contactbook;std::cout << "1. add contacts\n";contactbook.add("Bob", "18199357253");contactbook.add("Alice", "17300886371");contactbook.add("Linda", "18184538072");contactbook.add("Alice", "17300886371");std::cout << "\n2. display contacts\n";std::cout << "There are "<< contactbook.size() << " contacts.\n";contactbook.display();std::cout << "\n3. find contacts\n";contactbook.find("Bob");contactbook.find("David");std::cout << "\n4. remove contact\n";contactbook.remove("Bob");contactbook.remove("David"); }int main() {test();return 0; }
运行结果如下:
