第9天:构造函数与析构函数
学习目标
掌握对象的构造和析构过程,理解RAII原则,学会编写各种类型的构造函数和析构函数。
学习资源链接
📚 官方文档和教程
🎥 视频教程
📖 深入阅读
学习内容
1. 构造函数基础
- 默认构造函数
- 参数化构造函数
- 拷贝构造函数
- 移动构造函数(C++11)
- 委托构造函数(C++11)
2. 初始化列表
- 成员初始化列表的语法
- 初始化顺序
- 必须使用初始化列表的情况
- 性能优势
3. 析构函数
- 析构函数的作用
- 虚析构函数
- RAII原则
- 异常安全
4. 特殊成员函数
- 三/五/零法则
- 显式删除函数
- 显式默认函数
- 编译器生成的函数
5. 对象生命周期
- 构造顺序
- 析构顺序
- 局部对象和全局对象
- 异常处理中的对象管理
重点概念和代码示例
构造函数基础
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include <iostream> #include <string> #include <vector> using namespace std;
class Person { private: string name; int age; double height; vector<string> hobbies; public: Person() { cout << "默认构造函数被调用" << endl; name = "Unknown"; age = 0; height = 0.0; } Person(const string& n, int a, double h) { cout << "参数构造函数被调用: " << n << endl; name = n; age = a; height = h; } Person(const string& n, int a, double h, const vector<string>& hobbiesList) : name(n), age(a), height(h), hobbies(hobbiesList) { cout << "初始化列表构造函数被调用: " << name << endl; } Person(const Person& other) : name(other.name), age(other.age), height(other.height), hobbies(other.hobbies) { cout << "拷贝构造函数被调用: " << name << endl; } Person(const string& n) : Person(n, 0, 0.0) { cout << "委托构造函数被调用: " << name << endl; } ~Person() { cout << "析构函数被调用: " << name << endl; } void displayInfo() const { cout << "姓名: " << name << ", 年龄: " << age << ", 身高: " << height; if (!hobbies.empty()) { cout << ", 爱好: "; for (const auto& hobby : hobbies) { cout << hobby << " "; } } cout << endl; } const string& getName() const { return name; } };
void constructorDemo() { cout << "=== 构造函数演示 ===" << endl; Person p1; Person p2("Alice", 25, 165.5); vector<string> hobbies = {"阅读", "游泳", "编程"}; Person p3("Bob", 30, 175.0, hobbies); Person p4("Charlie"); Person p5 = p2; Person p6(p3); cout << "\n对象信息:" << endl; p1.displayInfo(); p2.displayInfo(); p3.displayInfo(); p4.displayInfo(); p5.displayInfo(); p6.displayInfo(); cout << "\n函数结束,开始析构..." << endl; }
|
初始化列表详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| class InitializationDemo { private: const int constantMember; int& referenceMember; string name; vector<int> numbers; static int objectCount; public:
InitializationDemo(int value, int& ref, const string& n) : constantMember(value), referenceMember(ref), name(n), numbers(10, 0) { ++objectCount; cout << "InitializationDemo构造完成,对象编号: " << objectCount << endl; } InitializationDemo(const InitializationDemo& other) : constantMember(other.constantMember), referenceMember(other.referenceMember), name(other.name), numbers(other.numbers) { ++objectCount; cout << "拷贝构造完成,对象编号: " << objectCount << endl; } ~InitializationDemo() { cout << "析构对象编号: " << objectCount-- << endl; } void displayInfo() const { cout << "常量成员: " << constantMember << ", 引用成员: " << referenceMember << ", 名称: " << name << ", 数组大小: " << numbers.size() << endl; } static void showInitializationOrder() { cout << "\n=== 初始化顺序演示 ===" << endl; cout << "成员初始化顺序由声明顺序决定,而非初始化列表顺序!" << endl; } };
int InitializationDemo::objectCount = 0;
void initializationListDemo() { cout << "\n=== 初始化列表演示 ===" << endl; int refTarget = 42; InitializationDemo obj1(100, refTarget, "Object1"); obj1.displayInfo(); InitializationDemo obj2 = obj1; obj2.displayInfo(); InitializationDemo::showInitializationOrder(); }
|
RAII和资源管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| class RAIIDemo { private: int* data; size_t size; string resourceName; public: RAIIDemo(const string& name, size_t s) : resourceName(name), size(s) { cout << "获取资源: " << resourceName << endl; data = new int[size]; for (size_t i = 0; i < size; i++) { data[i] = static_cast<int>(i + 1); } } RAIIDemo(const RAIIDemo& other) : resourceName(other.resourceName + "_copy"), size(other.size) { cout << "拷贝资源: " << resourceName << endl; data = new int[size]; for (size_t i = 0; i < size; i++) { data[i] = other.data[i]; } } RAIIDemo& operator=(const RAIIDemo& other) { cout << "赋值操作: " << resourceName << " = " << other.resourceName << endl; if (this != &other) { delete[] data; size = other.size; resourceName = other.resourceName + "_assigned"; data = new int[size]; for (size_t i = 0; i < size; i++) { data[i] = other.data[i]; } } return *this; } ~RAIIDemo() { cout << "释放资源: " << resourceName << endl; delete[] data; } int& operator[](size_t index) { if (index >= size) { throw out_of_range("Index out of range"); } return data[index]; } const int& operator[](size_t index) const { if (index >= size) { throw out_of_range("Index out of range"); } return data[index]; } size_t getSize() const { return size; } const string& getName() const { return resourceName; } void display() const { cout << resourceName << " ["; for (size_t i = 0; i < size; i++) { cout << data[i]; if (i < size - 1) cout << ", "; } cout << "]" << endl; } };
void raiiDemo() { cout << "\n=== RAII演示 ===" << endl; try { RAIIDemo resource1("Resource1", 5); resource1.display(); RAIIDemo resource2 = resource1; resource2.display(); resource1[0] = 100; resource2[1] = 200; cout << "修改后:" << endl; resource1.display(); resource2.display(); RAIIDemo resource3("Resource3", 3); resource3 = resource1; resource3.display(); cout << "\n测试异常安全性:" << endl; try { int value = resource1[10]; } catch (const exception& e) { cout << "捕获异常: " << e.what() << endl; } cout << "\n函数结束,RAII自动清理资源..." << endl; } catch (...) { cout << "发生异常,但RAII确保资源被正确释放" << endl; } }
|
实践练习
练习1:智能数组类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
| template<typename T> class SmartArray { private: T* data; size_t size; size_t capacity; void resize(size_t newCapacity) { T* newData = new T[newCapacity]; for (size_t i = 0; i < size; i++) { newData[i] = data[i]; } delete[] data; data = newData; capacity = newCapacity; } public: SmartArray() : data(nullptr), size(0), capacity(0) { cout << "SmartArray默认构造" << endl; } explicit SmartArray(size_t initialCapacity) : data(new T[initialCapacity]), size(0), capacity(initialCapacity) { cout << "SmartArray构造,容量: " << capacity << endl; } SmartArray(size_t count, const T& value) : data(new T[count]), size(count), capacity(count) { cout << "SmartArray构造,大小: " << size << ",初始值: " << value << endl; for (size_t i = 0; i < size; i++) { data[i] = value; } } SmartArray(const SmartArray& other) : data(new T[other.capacity]), size(other.size), capacity(other.capacity) { cout << "SmartArray拷贝构造,大小: " << size << endl; for (size_t i = 0; i < size; i++) { data[i] = other.data[i]; } } SmartArray(SmartArray&& other) noexcept : data(other.data), size(other.size), capacity(other.capacity) { cout << "SmartArray移动构造,大小: " << size << endl; other.data = nullptr; other.size = 0; other.capacity = 0; } ~SmartArray() { cout << "SmartArray析构,大小: " << size << endl; delete[] data; } SmartArray& operator=(const SmartArray& other) { cout << "SmartArray拷贝赋值" << endl; if (this != &other) { delete[] data; size = other.size; capacity = other.capacity; data = new T[capacity]; for (size_t i = 0; i < size; i++) { data[i] = other.data[i]; } } return *this; } SmartArray& operator=(SmartArray&& other) noexcept { cout << "SmartArray移动赋值" << endl; if (this != &other) { delete[] data; data = other.data; size = other.size; capacity = other.capacity; other.data = nullptr; other.size = 0; other.capacity = 0; } return *this; } void push_back(const T& value) { if (size >= capacity) { size_t newCapacity = capacity == 0 ? 1 : capacity * 2; resize(newCapacity); } data[size++] = value; } T& operator[](size_t index) { if (index >= size) throw out_of_range("Index out of range"); return data[index]; } const T& operator[](size_t index) const { if (index >= size) throw out_of_range("Index out of range"); return data[index]; } size_t getSize() const { return size; } size_t getCapacity() const { return capacity; } bool empty() const { return size == 0; } void display() const { cout << "SmartArray ["; for (size_t i = 0; i < size; i++) { cout << data[i]; if (i < size - 1) cout << ", "; } cout << "] (size: " << size << ", capacity: " << capacity << ")" << endl; } };
void exercise1() { cout << "\n=== 练习1:智能数组类 ===" << endl; SmartArray<int> arr1; SmartArray<int> arr2(5); SmartArray<int> arr3(3, 100); cout << "\n初始状态:" << endl; arr1.display(); arr2.display(); arr3.display(); cout << "\n添加元素:" << endl; for (int i = 1; i <= 8; i++) { arr1.push_back(i * 10); if (i % 3 == 0) arr1.display(); } for (int i = 1; i <= 3; i++) { arr2.push_back(i); } arr2.display(); cout << "\n拷贝操作:" << endl; SmartArray<int> arr4 = arr1; arr4.display(); SmartArray<int> arr5; arr5 = arr3; arr5.display(); cout << "\n修改元素:" << endl; arr4[0] = 999; arr4.display(); arr1.display(); cout << "\n函数结束,开始析构..." << endl; }
|
练习2:字符串类实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
| class MyString { private: char* str; size_t length; void copyString(const char* source) { if (source) { length = strlen(source); str = new char[length + 1]; strcpy(str, source); } else { length = 0; str = new char[1]; str[0] = '\0'; } } public: MyString() : str(nullptr), length(0) { cout << "MyString默认构造" << endl; str = new char[1]; str[0] = '\0'; } MyString(const char* cstr) { cout << "MyString从C字符串构造: " << (cstr ? cstr : "nullptr") << endl; copyString(cstr); } MyString(const MyString& other) { cout << "MyString拷贝构造: " << other.str << endl; copyString(other.str); } MyString(MyString&& other) noexcept : str(other.str), length(other.length) { cout << "MyString移动构造: " << str << endl; other.str = nullptr; other.length = 0; } ~MyString() { cout << "MyString析构: " << (str ? str : "nullptr") << endl; delete[] str; } MyString& operator=(const MyString& other) { cout << "MyString拷贝赋值: " << other.str << endl; if (this != &other) { delete[] str; copyString(other.str); } return *this; } MyString& operator=(MyString&& other) noexcept { cout << "MyString移动赋值: " << other.str << endl; if (this != &other) { delete[] str; str = other.str; length = other.length; other.str = nullptr; other.length = 0; } return *this; } MyString& operator=(const char* cstr) { cout << "MyString从C字符串赋值: " << (cstr ? cstr : "nullptr") << endl; delete[] str; copyString(cstr); return *this; } MyString operator+(const MyString& other) const { size_t newLength = length + other.length; char* newStr = new char[newLength + 1]; strcpy(newStr, str); strcat(newStr, other.str); MyString result; delete[] result.str; result.str = newStr; result.length = newLength; return result; } char& operator[](size_t index) { if (index >= length) throw out_of_range("Index out of range"); return str[index]; } const char& operator[](size_t index) const { if (index >= length) throw out_of_range("Index out of range"); return str[index]; } bool operator==(const MyString& other) const { return strcmp(str, other.str) == 0; } bool operator<(const MyString& other) const { return strcmp(str, other.str) < 0; } size_t size() const { return length; } bool empty() const { return length == 0; } const char* c_str() const { return str; } friend ostream& operator<<(ostream& os, const MyString& myStr) { os << myStr.str; return os; } friend istream& operator>>(istream& is, MyString& myStr) { char buffer[1000]; is >> buffer; myStr = buffer; return is; } };
void exercise2() { cout << "\n=== 练习2:字符串类实现 ===" << endl; MyString str1; MyString str2("Hello"); MyString str3 = str2; cout << "\n初始字符串:" << endl; cout << "str1: \"" << str1 << "\"" << endl; cout << "str2: \"" << str2 << "\"" << endl; cout << "str3: \"" << str3 << "\"" << endl; cout << "\n赋值操作:" << endl; str1 = "World"; str3 = str1; cout << "str1: \"" << str1 << "\"" << endl; cout << "str3: \"" << str3 << "\"" << endl; cout << "\n字符串拼接:" << endl; MyString str4 = str2 + MyString(" ") + str1; cout << "str4: \"" << str4 << "\"" << endl; cout << "\n字符访问:" << endl; cout << "str4[0] = " << str4[0] << endl; str4[0] = 'h'; cout << "修改后 str4: \"" << str4 << "\"" << endl; cout << "\n比较操作:" << endl; cout << "str2 == str3: " << (str2 == str3) << endl; cout << "str1 < str2: " << (str1 < str2) << endl; cout << "\n移动语义:" << endl; MyString str5 = MyString("Temporary"); str5 = MyString("Another Temp"); cout << "\n函数结束,开始析构..." << endl; }
|
练习3:异常安全的资源管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
| class FileManager { private: string filename; FILE* file; bool isOpen; public: explicit FileManager(const string& name) : filename(name), file(nullptr), isOpen(false) { cout << "FileManager构造: " << filename << endl; file = fopen(filename.c_str(), "w+"); if (file) { isOpen = true; cout << "文件打开成功: " << filename << endl; } else { cout << "文件打开失败: " << filename << endl; throw runtime_error("无法打开文件: " + filename); } } FileManager(const FileManager&) = delete; FileManager& operator=(const FileManager&) = delete; FileManager(FileManager&& other) noexcept : filename(move(other.filename)), file(other.file), isOpen(other.isOpen) { cout << "FileManager移动构造: " << filename << endl; other.file = nullptr; other.isOpen = false; } FileManager& operator=(FileManager&& other) noexcept { cout << "FileManager移动赋值: " << other.filename << endl; if (this != &other) { close(); filename = move(other.filename); file = other.file; isOpen = other.isOpen; other.file = nullptr; other.isOpen = false; } return *this; } ~FileManager() { cout << "FileManager析构: " << filename << endl; close(); } bool write(const string& data) { if (!isOpen || !file) { cout << "文件未打开,无法写入" << endl; return false; } size_t written = fwrite(data.c_str(), 1, data.length(), file); fflush(file); cout << "写入 " << written << " 字节到 " << filename << endl; return written == data.length(); } string read() { if (!isOpen || !file) { cout << "文件未打开,无法读取" << endl; return ""; } fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); if (size <= 0) return ""; string content(size, '\0'); size_t bytesRead = fread(&content[0], 1, size, file); content.resize(bytesRead); cout << "从 " << filename << " 读取 " << bytesRead << " 字节" << endl; return content; } void close() { if (file) { fclose(file); file = nullptr; isOpen = false; cout << "文件关闭: " << filename << endl; } } bool isFileOpen() const { return isOpen; } const string& getFilename() const { return filename; } };
void exercise3() { cout << "\n=== 练习3:异常安全的资源管理 ===" << endl; try { FileManager fm1("test1.txt"); fm1.write("Hello, World!\n"); fm1.write("这是第二行\n"); string content = fm1.read(); cout << "读取的内容:\n" << content << endl; cout << "\n移动语义测试:" << endl; FileManager fm2("test2.txt"); fm2.write("原始文件内容\n"); FileManager fm3 = move(fm2); fm3.write("移动后添加的内容\n"); cout << "fm3内容: " << fm3.read() << endl; cout << "\n异常测试:" << endl; try { FileManager fm4("/nonexistent/path/file.txt"); } catch (const exception& e) { cout << "捕获异常: " << e.what() << endl; } cout << "\n正常结束,RAII自动清理资源..." << endl; } catch (const exception& e) { cout << "程序异常: " << e.what() << endl; cout << "但RAII确保资源被正确释放" << endl; } }
|
学习检查点
完整示例程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <iostream> #include <string> #include <vector> #include <stdexcept> #include <cstring> #include <cstdio> using namespace std;
int main() { cout << "=== C++ 构造函数与析构函数学习 ===" << endl; try { constructorDemo(); initializationListDemo(); raiiDemo(); exercise1(); exercise2(); exercise3(); } catch (const exception& e) { cout << "程序异常: " << e.what() << endl; } cout << "\n程序结束" << endl; return 0; }
|
返回第二周 | 上一天:类与对象基础 | 下一天:继承