文章目录
- 一、构造函数
- 1.1定义
- 1.2语法
- 1.3特性
- 二、析构函数
- 2.1定义
- 2.2语法
- 2.3特性
- 三、拷贝构造函数
- 3.1定义
- 3.2语法
- 3.3特性
- 3.4浅拷贝
- 3.4.1定义
- 3.4.2浅拷贝的风险
- 3.5深拷贝
一、构造函数
1.1定义
在C++中,构造函数(Constructor) 是一种特殊的成员函数,用于在创建对象时初始化其成员变量。构造函数的名称必须与类名相同,且没有返回类型(包括 void)。构造函数在对象创建时自动调用,确保对象处于有效状态。
1.2语法
class ClassName {
public:ClassName(){内容} // 默认构造函数(无参)ClassName(参数列表){内容} // 带参构造函数// ... 其他成员函数
};
示例:
class Date {
public:Date(){_year = 1970;_month = 1;_day = 1;// 默认构造函数实现。如若未定义则是随机值。}Date(int year, int month, int day){_year = year;_month = month;_day = day;// 带参构造函数}void print() {cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main() {Date d1; // 调用默认构造函数Date d2(2023, 5, 15); // 调用带参构造函数Date d3{}; // C++11统一初始化方式调用默认构造函数d1.print(); // 输出: 1970-1-1d2.print(); // 输出: 2023-5-15d3.print(); // 输出: 1970-1-1return 0;
}
1.3特性
构造函数的主要任务并不是开空间创建对象,而是初始化对象。 它具有以下特点:
- 1.函数名与类名相同。
- 2.无返回值。
- 3.对象实例化时编译器自动调用对应的构造函数。
- 4.构造函数可以重载。
- 5.如果未写构造函数,编译器默认生成的是"类名();"
二、析构函数
2.1定义
在C++中,析构函数(Destructor) 是一种特殊的成员函数,用于在对象生命周期结束时自动执行清理工作(如释放内存、关闭文件等)。它的名称是在类名前加 ~,没有返回类型,也不接受任何参数。一般在有动态内存申请的时候要写析构函数。没动态申请的一般不需要写析构。
2.2语法
class ClassName {
public:~ClassName(); // 析构函数,函数体定义默认没有,也可以自己定义。如下文示例。
};
示例:
class Date {
public:~Date(){cout << "Date对象被销毁" << endl;}
private:int year;int month;int day;
};int main()
{Date a;return 0;
}
//程序结束后会打印"Date对象被销毁"。
2.3特性
- 1.自动调用。
- 2.不能重载。
三、拷贝构造函数
3.1定义
拷贝构造函数是构造函数的一种重载形式,专门用于用已存在的对象创建新对象,核心是实现对象的“复制”。它的参数必须是同类对象的引用(通常加 const ,防止意外修改原对象),这是与普通构造函数的关键区别。
3.2语法
class MyClass {
public:// 拷贝构造函数声明MyClass(const MyClass& other);
};// 拷贝构造函数实现
MyClass::MyClass(const MyClass& other) {// 拷贝逻辑
}
3.3特性
-
1.参数类型:
①必须是对同类对象的const引用②使用引用避免无限递归
③const确保不修改源对象
-
2.无返回值:构造函数没有返回类型
-
3.通常不声明为explicit:允许隐式拷贝构造
3.4浅拷贝
3.4.1定义
-
1.逐成员复制:简单复制对象的所有非静态成员变量
-
2.指针共享:对于指针成员,仅复制指针值(地址),不复制指向的内容
-
3.默认行为:编译器生成的默认拷贝构造函数执行的就是浅拷贝
示例:
class Time
{
public:Time(){_hour = 1;_minute = 1;_second = 1;}Time(const Time& t)//这就是浅拷贝{_hour = t._hour;_minute = t._minute;_second = t._second;}
private:int _hour;int _minute;int _second;
};
3.4.2浅拷贝的风险
双重释放问题:
假如arr2是arr1的拷贝。
当arr1和arr2离开作用域时:
先调用arr2的析构函数释放内存。
再调用arr1的析构函数再次释放同一内存 → 程序崩溃
3.5深拷贝
深拷贝是指:
-
1.创建新对象时完全复制所有数据
-
2.对指针成员分配新内存并复制内容
-
3.副本与原对象完全独立,不共享任何资源
示例:(栈)
class SafeStack {
private:int* data;int capacity;int topIndex;public:// 构造函数SafeStack(int size): capacity(size), topIndex(-1), data(new int[size]) {}// 深拷贝构造函数SafeStack(const SafeStack& other): capacity(other.capacity),topIndex(other.topIndex),data(new int[other.capacity]) {// 复制栈中所有元素for (int i = 0; i <= topIndex; ++i) {data[i] = other.data[i];}}// 深拷贝赋值运算符SafeStack& operator=(const SafeStack& other) {if (this != &other) { // 自赋值检查// 创建临时副本int* newData = new int[other.capacity];// 复制数据for (int i = 0; i <= other.topIndex; ++i) {newData[i] = other.data[i];}// 替换旧数据(异常安全)delete[] data;data = newData;capacity = other.capacity;topIndex = other.topIndex;}return *this;}// 移动构造函数(C++11)SafeStack(SafeStack&& other) noexcept: data(other.data),capacity(other.capacity),topIndex(other.topIndex) {other.data = nullptr;other.capacity = 0;other.topIndex = -1;}// 析构函数~SafeStack() {delete[] data;}void push(int value) {if (topIndex == capacity - 1) {throw std::overflow_error("Stack is full");}data[++topIndex] = value;}int pop() {if (topIndex == -1) {throw std::underflow_error("Stack is empty");}return data[topIndex--];}void print() {std::cout << "Stack: [ ";for (int i = 0; i <= topIndex; ++i) {std::cout << data[i] << " ";}std::cout << "]\n";}
};int main() {SafeStack s1(5);s1.push(1);s1.push(2);s1.push(3);// 测试拷贝构造函数SafeStack s2 = s1; // 深拷贝// 修改s1不影响s2s1.pop();s1.push(99);// 测试赋值运算符SafeStack s3(2);s3 = s1; // 深拷贝赋值s1.print(); // 输出: Stack: [ 1 2 99 ]s2.print(); // 输出: Stack: [ 1 2 3 ]s3.print(); // 输出: Stack: [ 1 2 99 ]// 测试移动语义SafeStack s4 = std::move(s1);s1.print(); // 输出: Stack: [ ] (已移动)s4.print(); // 输出: Stack: [ 1 2 99 ]return 0;
}