request-free-img

C++到底有多复杂?构造函数详解:新手必看

仅仅一个构造函数的概念就可以把新手逼疯,不信你看。

在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++的各种构造函数,你迷糊了没?哈哈哈哈哈哈哈


更多问题探讨,请关注公众号:程序员角