实验3 类和对象_基础编程2
任务一:
#pragma once #pragma once #include <iostream> #include <vector> #include <algorithm> #include "button.h" // 窗口类 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"; else buttons.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; }
#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"; }
#include "window.h" #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(); }

问题一:是。Window 类包含 vector<Button>成员,体现 “窗口包含按钮” 的 has-a 关系。
问题二:优点:外部可直接调用该函数查询按钮,增加功能灵活性。
风险:暴露内部实现细节,外部调用可能破坏封装性;若后续修改内部按钮存储方式,需同步修改外部依赖代码。
public:用户需要调用的功能,体现类的对外服务,非内部细节。
private:仅为内部实现的辅助功能,或操作私有数据易破坏对象状态的函数。
问题三:
接口 1:性能高,无字符串拷贝;安全,外部无法修改内部数据。
接口 2:性能低,有拷贝开销;安全,外部修改不影响内部,但易产生悬空引用。
问题四:
能正常运行。差别:push_back 先创建临时 Button 再拷贝 / 移动;emplace_back 直接在容器内构造对象,无临时对象开销,更高效。
实验二:
#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); }

问题一:
第一行:创建 v1,包含 5 个值为 42 的 int 元素。
第二行:通过拷贝构造创建 v2,内容与 v1 相同。
v1、v2 各有 5 个值为 42 的数据项。
问题二:
执行后:v1.size () 是 2(包含 2 个 vector<int>子容器);v2.size () 是 2(拷贝自 v1);v1 [0].size () 是 3(第一个子容器有 3 个元素)。
问题三:
效果不同,
v1.at (0) = -1:会检查下标合法性,若越界抛出 out_of_range 异常。
v1 [0] = -1:不检查下标,越界会导致未定义行为。
问题四:
不能输出 17。因为 v1.at (0) 返回的是 v1 第一个子容器的引用,r 是该子容器的引用,r.size () 是子容器的元素个数(初始为 3),不是 v1 的大小。
优势:避免拷贝子容器,节省内存、提升效率。
问题:若 v1 被销毁或 v1 [0] 被修改,const 引用会悬空,引发未定义行为。
问题五:
标准库 vector 的拷贝构造是深复制:拷贝后两个 vector 的元素独立存储,修改其中一个不影响另一个。
当 v 是 vector<int>时,v.at (0) 返回 int&;
当 v 是 const vector<int>时,v.at (0) 返回 const int&。
at () 必须提供 const 重载版本:确保 const vector 对象调用 at () 时,返回不可修改的引用,符合 const 对象的只读特性。
实验三:
#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; }
#include "vectorInt.h" #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'; }

问题一:
实验五:
#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; void sort(); 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(); } int ContactBook::index(const std::string& name) const { for (size_t i = 0; i < contacts.size(); ++i) { if (contacts[i].get_name() == name) { return i; } } return -1; } void ContactBook::sort() { std::sort(contacts.begin(), contacts.end(), [](const Contact& a, const Contact& b) { return a.get_name() < b.get_name(); }); }
#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; }
#include "contactBook.h" 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(); }


浙公网安备 33010602011771号