仅仅一个构造函数的概念就可以把新手逼疯,不信你看。
在C++中,构造函数有:
- 默认构造函数
- 带参数的构造函数
- 拷贝构造函数
- 移动构造函数
- 转换构造函数
- 委托构造函数
今天我就给你讲讲C++的各种构造函数以及它们的作用。

完整代码示例
#include <iostream>
class MyClass {
public:
int* data;
MyClass() : data(new int(0)) {
std::cout << "默认构造函数" << std::endl;
}
MyClass(int val) : data(new int(val)) {
std::cout << "带参数的构造函数" << std::endl;
}
MyClass(const MyClass& other)
: data(new int(*other.data))
{
std::cout << "拷贝构造函数" << std::endl;
}
MyClass(MyClass&& other) noexcept
: data(other.data) {
other.data = nullptr;
std::cout << "移动构造函数" << std::endl;
}
explicit MyClass(double val)
: data(new int(static_cast<int>(val)))
{
std::cout << "转换构造函数" << std::endl;
}
MyClass(char c) : MyClass()
{
*data = c; std::cout << "委托构造函数" << std::endl;
}
~MyClass() {
delete data; std::cout << "析构函数" << std::endl;
}
};
int main() {
MyClass a; // 默认
MyClass b(10); // 带参数
MyClass c(b); // 拷贝
MyClass d(std::move(b)); // 移动
MyClass e(3.14); // 转换
MyClass e1 = 10; // 转换
MyClass f('A'); // 委托
return 0;
}
在这个类中实现了各种不同的构造函数,下面我们一个个来讲解它们的实现方式以及作用。
1. 默认构造函数
它的主要作用是在对象被创建时,没有提供初始化参数的情况下用于初始化对象的成员变量。
也就是当我们创建对象a的时候,并没有提供任何参数,此时会调用默认的构造函数。
在这个默认构造函数中,为data申请了一块内存。
需要注意的是,如果类中没有定义任何构造函数,编译器会自动生成一个默认构造函数。
2. 带参数的构造函数
带参数的构造函数它可以接受一个或多个参数,用于根据参数个数和类型来初始化对象。
例如:MyClass b(10);
在我们的示例中我们实现了一个带int参数的构造函数,所以当我们实例化对象b的时候,传入的是一个Int型的参数10,就会调用这个带Int参数的构造函数。
需要注意的是,你可以实现多个带参数的构造函数来匹配不同的参数类型。
3. 拷贝构造函数
拷贝构造函数(Copy Constructor)用于创建一个对象,并用已有的对象来初始化它。本质上,它实现了对象的深拷贝或浅拷贝。
在这个拷贝构造函数中我们也为data申请了一块新的内存,并且用另一个类对象的值来初始化它,这就叫深拷贝。
拷贝构造函数以常引用方式接收同类型对象,避免不必要的拷贝。
例如:MyClass c(b);
我们在实例化对象c的时候,传入了对象b,这会触发拷贝构造函数的调用。
需要注意的是拷贝构造函数中,如果省略引用符号 & 会导致无限递归,因为那样的话在参数传递时也会触发调用拷贝构造函数。
4. 移动构造函数
移动构造函数(Move Constructor)是C++11引入的一种特殊构造函数,用于从临时对象或可移动对象中“窃取”资源,而不是进行深拷贝,从而提高程序性能。
在这个移动构造函数中,它刚好和拷贝构造函数相反,它没有为data去申请一块新的内存,而是直接将data指向了传入类对象的data地址。同时将传入类对象的data地址置为空,从而实现“窃取”传入类对象资源的目的,以此来提升程序的性能。
需要注意的是,移动构造函数中接受一个右值引用。
例如:MyClass d(std::move(b));
我们实例化d的时候,将b左值转为右值,然后传入,这会触发调用移动构造函数。
5. 转换构造函数
在C++中,所有的单参数构造函数其实都是转换构造函数,它用于将其他类型转换为类对象。
在我们的示例中,它接受一个double类型的参数,并将它转换为一个类。
其实前边这个带一个Int参数的构造函数也可以是转换构造函数。
当转换构造函数没有添加explicit关键字时,它允许隐式转换,也就是我们可以这样调用:
MyClass e1 = 10;
而添加explicit关键字后,则只能采用直接构造的方式调用。
6. 委托构造函数
委托构造函数(Delegating Constructor)允许一个构造函数调用另一个构造函数,以减少代码重复并提高可维护性。
在我们的示例类中,我们的委托构造函数又调用了默认构造函数。
委托构造函数的目的仅仅是为了减少代码重复,从而提供更清晰的初始化流程。
总结
现在关于C++的各种构造函数,你迷糊了没?哈哈哈哈哈哈哈


