跳到正文
孔乙己

C++ 构造函数

默认、初始化、拷贝、移动、委托与转换构造函数各自的用途,以及拷贝构造/赋值运算符中深拷贝与浅拷贝的区别。

编程,C++1分钟阅读

  • 默认构造函数是一个没有任何参数的构造函数,当对象被创建时调用。
  • 如果没有为类定义任何构造函数,编译器将会自动生成一个默认构造函数
  • 默认构造函数用于初始化对象的成员变量,通常会将它们设置为默认值

  • 初始化构造函数接受一个或多个参数,并使用这些参数来初始化对象的成员变量。
  • 它允许在创建对象时进行初始化,而不是在对象创建后再进行赋值操作。

  • 拷贝构造函数是一种特殊的构造函数,它在创建一个新对象时,使用同一类中另一个对象的数据进行初始化。
  • 通常用于复制对象,例如当对象作为函数参数传递时或者通过值传递方式返回对象时。

  • 移动构造函数是C++11引入的新特性,它允许在对象的资源被转移时进行高效初始化。
  • 移动构造函数通常与右值引用一起使用,以提高性能并避免不必要的内存赋值操作。

  • 委托构造函数允许一个构造函数调用同一类中的另一个构造函数来完成初始化。
  • 这样可以避免代码重复,并提高代码的可维护性。

  • 转换构造函数是一种特殊的构造函数,它将一个不同类型的对象转换为当前类的对象

  • 当需要从一个类型隐式转换为另一个类型时,转换构造函数就会起作用。

    #include <iostream>
    #include <string>
    class MyClass {
    public:
    int data;
    // 默认构造函数
    MyClass() {
    data = 0;
    std::cout << "Default constructor called." << std::endl;
    }
    // 初始化构造函数
    MyClass(int value) {
    data = value;
    std::cout << "Parameterized constructor called with value: " << value << std::endl;
    }
    // 拷贝构造函数
    MyClass(const MyClass& other) {
    data = other.data;
    std::cout << "Copy constructor called." << std::endl;
    }
    // 移动构造函数
    MyClass(MyClass&& other) noexcept {
    data = std::move(other.data);
    std::cout << "Move constructor called." << std::endl;
    }
    // 委托构造函数
    MyClass(std::string message) : MyClass() {
    std::cout << message << std::endl;
    }
    // 转换构造函数
    explicit MyClass(double value) {
    data = static_cast<int>(value);
    std::cout << "Conversion constructor called with value: " << value << std::endl;
    }
    };
    int main() {
    // 默认构造函数
    MyClass obj1;
    // 初始化构造函数
    MyClass obj2(10);
    // 拷贝构造函数
    MyClass obj3 = obj2;
    // 移动构造函数
    MyClass obj4 = std::move(obj3);
    // 委托构造函数
    MyClass obj5("Delegating constructor called.");
    // 转换构造函数
    MyClass obj6 = 3.14;
    return 0;
    }

  • 如果没有提供自定义的拷贝构造函数,并且在使用时需要拷贝时,编译器将会生成一个默认的拷贝构造函数。这个默认的拷贝构造函数执行浅拷贝。

    class MyClass {
    public:
    int x;
    // 没有定义自定义拷贝构造函数
    };
    MyClass obj1;
    MyClass obj2 = obj1; // 调用默认的拷贝构造函数
  • 如果类中没有引用或常量成员变量,编译器会生成默认的拷贝构造函数

    class MyClass {
    public:
    int x;
    int& ref; // 引用成员变量
    const int y; // 常量成员变量
    MyClass(int a) : x(a), ref(x), y(a) {}
    // 没有定义自定义拷贝构造函数
    };
    MyClass obj1(10);
    MyClass obj2 = obj1; // 调用默认的拷贝构造函数

  • 与拷贝构造函数类似,如果你没有提供自定义的赋值运算符重载函数,并且类中没有引用或常量成员变量,编译器会生成一个默认的赋值运算符重载函数。这个默认的赋值运算符执行成员变量的逐个拷贝,即浅拷贝。

  1. 浅拷贝(Shallow copy)
    • 浅拷贝是指简单地赋值对象的数据成员的值,而不涉及到动态分配的资源(如堆内存)的赋值。
    • 对于指针成员变量,浅拷贝仅仅复制指针的值,而不是复制指针所指向的内容。因此,如果两个对象共享同一个动态分配的内存块,当其中一个对象修改了内存块的内容时,另一个对象的内容也会受到影响。
    • 浅拷贝通常通过默认的拷贝构造函数或赋值运算符来实现。
  2. 深拷贝(Deep copy)
    • 深拷贝是指在拷贝对象时,对动态分配的资源进行复制,而不是简单地复制指针的值。
    • 对于指针成员变量,深拷贝会分配新的内存空间,并将原内存空间的内容复制到新内存空间中,这样每个对象都有自己独立的资源副本,修改一个对象的资源不会影响到其它对象。
    • 深拷贝通常需要通过自定义的拷贝构造函数或赋值运算符来实现。
#include <iostream>
class ShallowCopy {
public:
int* data;
// 默认构造函数
ShallowCopy(int value) {
data = new int(value);
}
// 拷贝构造函数(浅拷贝)
ShallowCopy(const ShallowCopy& other) {
data = other.data; // 浅拷贝,仅复制指针的值
}
// 析构函数
~ShallowCopy() {
delete data;
}
};
class DeepCopy {
public:
int* data;
// 默认构造函数
DeepCopy(int value) {
data = new int(value);
}
// 拷贝构造函数(深拷贝)
DeepCopy(const DeepCopy& other) {
data = new int(*other.data); // 深拷贝,复制指针所指向的内容
}
// 析构函数
~DeepCopy() {
delete data;
}
};
int main() {
ShallowCopy obj1(10);
ShallowCopy obj2 = obj1; // 浅拷贝,两个对象共享同一块内存
DeepCopy obj3(20);
DeepCopy obj4 = obj3; // 深拷贝,每个对象有自己独立的内存副本
// 修改 obj1 和 obj3 的数据
*(obj1.data) = 100;
*(obj3.data) = 200;
// 输出 obj2 和 obj4 的数据
std::cout << "obj2.data: " << *(obj2.data) << std::endl; // 应该输出 100
std::cout << "obj4.data: " << *(obj4.data) << std::endl; // 应该输出 20
return 0;
}

评论