C++ 构造函数完全指南

一、构造函数的基本分类

1.1 默认构造函数(Default Constructor)

没有参数或所有参数都有默认值的构造函数。

复制代码
class MyClass {
public:
    // 1. 显式默认构造函数
    MyClass() {
        data = 0;
        name = "default";
        std::cout << "Default constructor called\n";
    }
    
    // 2. 编译器生成的隐式默认构造函数
    // 如果没有任何构造函数,编译器会自动生成
    
private:
    int data;
    std::string name;
};

// 使用
MyClass obj1;           // 调用默认构造函数
MyClass obj2{};         // C++11 统一初始化
MyClass* obj3 = new MyClass();  // 动态分配

1.2 参数化构造函数(Parameterized Constructor)

带有参数的构造函数。

复制代码
class Point {
private:
    double x, y;
    
public:
    // 参数化构造函数
    Point(double xVal, double yVal) {
        x = xVal;
        y = yVal;
        std::cout << "Parameterized constructor: (" << x << ", " << y << ")\n";
    }
    
    // 带默认值的参数化构造函数
    Point(double xVal = 0.0, double yVal = 0.0, double zVal = 0.0) {
        x = xVal;
        y = yVal;
        std::cout << "Constructor with defaults called\n";
    }
};

// 使用
Point p1(10.5, 20.3);     // 调用参数化构造函数
Point p2(15.0);           // 使用默认值
Point p3{};               // 全部使用默认值

1.3 拷贝构造函数(Copy Constructor)

用同类型的另一个对象初始化新对象。

复制代码
class String {
private:
    char* buffer;
    size_t length;
    
public:
    // 普通构造函数
    String(const char* str) {
        length = strlen(str);
        buffer = new char[length + 1];
        strcpy(buffer, str);
        std::cout << "Regular constructor: " << buffer << "\n";
    }
    
    // 拷贝构造函数(深拷贝)先申请一个新的内存空间
    String(const String& other) {
        length = other.length;
        buffer = new char[length + 1];
        strcpy(buffer, other.buffer);
        std::cout << "Copy constructor: " << buffer << "\n";
    }
    
    // 拷贝构造函数(浅拷贝 - 通常不要这样做)
    // String(const String& other) : buffer(other.buffer), length(other.length) {}
    
    ~String() {
        delete[] buffer;
    }
    
    void print() const {
        std::cout << "String: " << (buffer ? buffer : "null") << "\n";
    }
};

// 使用拷贝构造函数的场景
void demonstrateCopyConstructor() {
    String s1("Hello");           // 普通构造函数
    
    // 场景1:直接初始化
    String s2(s1);                // 拷贝构造函数
    String s3 = s1;               // 拷贝构造函数(不是赋值!)
    
    // 场景2:传参
    void processString(String str);  // 值传递会调用拷贝构造函数
    processString(s1);
    
    // 场景3:返回值
    String createString() {
        String temp("Temp");
        return temp;              // 可能调用拷贝构造函数(NRVO优化可能避免)
    }
}

1.4 移动构造函数(Move Constructor)(C++11)

将资源从一个临时对象转移到新对象。

复制代码
class DynamicArray {
private:
    int* data;
    size_t size;
    
public:
    // 普通构造函数
    DynamicArray(size_t n) : size(n), data(new int[n]) {
        std::fill(data, data + size, 0);
        std::cout << "Regular constructor, size: " << size << "\n";
    }
    
    // 拷贝构造函数
    DynamicArray(const DynamicArray& other) : size(other.size), data(new int[other.size]) {
        std::copy(other.data, other.data + size, data);
        std::cout << "Copy constructor, size: " << size << "\n";
    }
    
    // 移动构造函数(C++11)
    DynamicArray(DynamicArray&& other) noexcept 
        : data(other.data), size(other.size) {  // 窃取资源
        other.data = nullptr;  // 置空原对象
        other.size = 0;
        std::cout << "Move constructor, size: " << size << "\n";
    }
    
    ~DynamicArray() {
        delete[] data;
    }
    
    // 移动赋值运算符(通常与移动构造函数一起实现)
    DynamicArray& operator=(DynamicArray&& other) noexcept {
        if (this != &other) {
            delete[] data;          // 释放现有资源
            data = other.data;      // 窃取资源
            size = other.size;
            other.data = nullptr;
            other.size = 0;
        }
        return *this;
    }
};

// 使用移动构造函数
void demonstrateMoveConstructor() {
    DynamicArray arr1(100);        // 普通构造函数
    
    // 场景1:从临时对象移动
    DynamicArray arr2(std::move(arr1));  // 显式移动
    
    // 场景2:从函数返回值移动
    auto createArray = []() -> DynamicArray {
        DynamicArray temp(50);
        // ... 操作 temp
        return temp;               // 可能调用移动构造函数
    };
    
    DynamicArray arr3 = createArray();  // 移动构造
    
    // 场景3:标准库容器中的移动
    std::vector<DynamicArray> arrays;
    arrays.push_back(DynamicArray(30));  // 移动构造
    arrays.emplace_back(40);             // 原地构造,无移动
}

1.5 委托构造函数(Delegating Constructor)(C++11)

一个构造函数调用同类的另一个构造函数。

复制代码
class Employee {
private:
    std::string name;
    int id;
    double salary;
    std::string department;
    
public:
    // 主构造函数(包含所有参数)
    Employee(const std::string& n, int i, double s, const std::string& d)
        : name(n), id(i), salary(s), department(d) {
        std::cout << "Main constructor called\n";
        validateData();
    }
    
    // 委托构造函数:委托给主构造函数
    Employee(const std::string& n, int i, double s)
        : Employee(n, i, s, "Unassigned") {  // 委托调用
        std::cout << "Delegating constructor (3 params)\n";
    }
    
    // 另一个委托构造函数
    Employee(const std::string& n, int i)
        : Employee(n, i, 0.0, "Unassigned") {  // 委托调用
        std::cout << "Delegating constructor (2 params)\n";
    }
    
    // 默认构造函数也委托
    Employee() : Employee("Unknown", 0, 0.0, "Unassigned") {
        std::cout << "Default delegating constructor\n";
    }
    
private:
    void validateData() {
        if (salary < 0) throw std::invalid_argument("Salary cannot be negative");
        if (id < 0) throw std::invalid_argument("ID cannot be negative");
    }
};

// 使用
Employee e1;                          // 调用默认委托构造函数
Employee e2("Alice", 1001);           // 调用2参数委托构造函数
Employee e3("Bob", 1002, 50000.0);    // 调用3参数委托构造函数
Employee e4("Charlie", 1003, 60000.0, "Engineering");  // 调用主构造函数

1.6 继承构造函数(Inheriting Constructor)(C++11)

派生类继承基类的构造函数。

复制代码
class Base {
protected:
    int baseValue;
    
public:
    Base() : baseValue(0) {
        std::cout << "Base default constructor\n";
    }
    
    Base(int val) : baseValue(val) {
        std::cout << "Base parameterized constructor: " << val << "\n";
    }
    
    Base(int val1, int val2) : baseValue(val1 + val2) {
        std::cout << "Base two-parameter constructor\n";
    }
};

class Derived : public Base {
private:
    int derivedValue;
    std::string name;
    
public:
    // C++11之前:需要手动重写所有基类构造函数
    /*
    Derived() : Base(), derivedValue(0), name("") {}
    Derived(int val) : Base(val), derivedValue(0), name("") {}
    Derived(int val1, int val2) : Base(val1, val2), derivedValue(0), name("") {}
    */
    
    // C++11:使用继承构造函数
    using Base::Base;  // 继承Base的所有构造函数
    
    // 可以添加额外的初始化
    Derived() : Base(), derivedValue(0), name("DerivedDefault") {
        std::cout << "Derived default constructor\n";
    }
    
    // 也可以定义新的构造函数
    Derived(const std::string& n) : Base(), derivedValue(0), name(n) {
        std::cout << "Derived string constructor: " << name << "\n";
    }
    
    void print() const {
        std::cout << "Base: " << baseValue 
                  << ", Derived: " << derivedValue 
                  << ", Name: " << name << "\n";
    }
};

// 使用
Derived d1;              // 调用Derived默认构造函数
Derived d2(42);          // 调用继承的Base(int)构造函数
Derived d3(10, 20);      // 调用继承的Base(int, int)构造函数  
Derived d4("Custom");    // 调用新的字符串构造函数

1.7 显式构造函数(Explicit Constructor)

防止隐式类型转换。

复制代码
class SmartPointer {
private:
    int* ptr;
    
public:
    // 显式构造函数 - 禁止隐式转换
    explicit SmartPointer(int* p = nullptr) : ptr(p) {
        std::cout << "Explicit constructor\n";
    }
    
    // 非显式构造函数 - 允许隐式转换
    SmartPointer(int value) : ptr(new int(value)) {
        std::cout << "Non-explicit constructor\n";
    }
    
    ~SmartPointer() {
        delete ptr;
    }
    
    int* get() const { return ptr; }
};

class Container {
private:
    SmartPointer sp;
    
public:
    // 接受SmartPointer参数的构造函数
    explicit Container(const SmartPointer& s) : sp(s) {}
    
    // 接受int指针的构造函数
    Container(int* p) : sp(p) {}  // 这里会调用SmartPointer的构造函数
};

void demonstrateExplicit() {
    int* rawPtr = new int(42);
    
    // 正常使用
    SmartPointer sp1(rawPtr);        // OK:直接初始化
    SmartPointer sp2 = SmartPointer(rawPtr);  // OK:显式转换
    
    // 隐式转换(被explicit阻止)
    // SmartPointer sp3 = rawPtr;     // ❌ 错误:不能隐式转换
    
    Container c1(sp1);               // OK:传递SmartPointer对象
    Container c2(rawPtr);            // OK:调用Container(int*)构造函数
    
    // 隐式转换到SmartPointer再构造Container
    // Container c3 = rawPtr;         // ❌ 错误:需要两次隐式转换
}

二、特殊用途构造函数

2.1 转换构造函数(Conversion Constructor)

允许从其他类型隐式转换的构造函数。

复制代码
class Complex {
private:
    double real, imag;
    
public:
    // 转换构造函数:从double到Complex
    Complex(double r, double i = 0.0) : real(r), imag(i) {
        std::cout << "Conversion constructor: " << r << " + " << i << "i\n";
    }
    
    // 转换构造函数:从std::string到Complex
    Complex(const std::string& str) {
        // 解析字符串如 "3.14+2.71i"
        size_t plusPos = str.find('+');
        size_t iPos = str.find('i');
        
        if (plusPos != std::string::npos && iPos != std::string::npos) {
            real = std::stod(str.substr(0, plusPos));
            imag = std::stod(str.substr(plusPos + 1, iPos - plusPos - 1));
        } else {
            real = std::stod(str);
            imag = 0.0;
        }
        std::cout << "String conversion constructor: " << str << "\n";
    }
    
    void display() const {
        std::cout << real << " + " << imag << "i\n";
    }
    
    // 类型转换运算符(与转换构造函数配对)
    explicit operator double() const {
        return real;  // 只返回实部
    }
};

void demonstrateConversion() {
    Complex c1(3.14);                // OK:调用转换构造函数
    Complex c2 = 2.71;               // OK:隐式转换(没有explicit)
    
    // 多个参数的转换
    Complex c3 = 1.0;                // imag默认为0
    Complex c4 = Complex(1.0, 2.0);  // 显式调用
    
    // 字符串转换
    Complex c5("5.0+3.0i");          // 字符串到Complex
    Complex c6 = std::string("2.0"); // 隐式转换
    
    // 在表达式中使用
    Complex result = c1 + 10.5;      // 10.5被隐式转换为Complex(10.5, 0)
    
    // 类型转换运算符
    double realPart = static_cast<double>(c1);  // 显式转换
}

2.2 constexpr 构造函数(C++11)

在编译期求值的构造函数。

复制代码
class Point3D {
private:
    double x, y, z;
    
public:
    // constexpr构造函数 - 可以在编译期调用
    constexpr Point3D(double xVal = 0.0, double yVal = 0.0, double zVal = 0.0)
        : x(xVal), y(yVal), z(zVal) {
        // constexpr构造函数体必须为空或只包含简单语句
    }
    
    // constexpr成员函数
    constexpr double getX() const { return x; }
    constexpr double getY() const { return y; }
    constexpr double getZ() const { return z; }
    
    constexpr double distanceSquared() const {
        return x * x + y * y + z * z;
    }
    
    // C++14起可以在constexpr函数中有更多操作
    constexpr void translate(double dx, double dy, double dz) {
        x += dx;
        y += dy;
        z += dz;
    }
};

// 编译期计算
constexpr Point3D origin;                    // 编译期构造
constexpr Point3D p1(1.0, 2.0, 3.0);         // 编译期构造
constexpr double dist = p1.distanceSquared(); // 编译期计算
constexpr Point3D p2 = []() {                // C++17起
    Point3D p(1.0, 1.0, 1.0);
    p.translate(1.0, 1.0, 1.0);  // (2.0, 2.0, 2.0)
    return p;
}();

// 运行时使用(与普通类无区别)
Point3D runtimePoint(rand() % 100, rand() % 100, rand() % 100);

2.3 模板构造函数

基于模板参数的构造函数。

复制代码
template<typename T>
class Container {
private:
    T* data;
    size_t capacity;
    size_t size;
    
public:
    // 普通构造函数
    Container(size_t cap = 10) : capacity(cap), size(0) {
        data = new T[capacity];
        std::cout << "Container<" << typeid(T).name() 
                  << "> constructor, capacity: " << capacity << "\n";
    }
    
    // 模板构造函数:从其他类型的Container转换
    template<typename U>
    Container(const Container<U>& other) 
        : capacity(other.getCapacity()), size(other.getSize()) {
        data = new T[capacity];
        
        // 转换每个元素
        for (size_t i = 0; i < size; ++i) {
            data[i] = static_cast<T>(other[i]);
        }
        
        std::cout << "Template conversion constructor from Container<" 
                  << typeid(U).name() << ">\n";
    }
    
    // 模板构造函数:从迭代器范围构造
    template<typename InputIt>
    Container(InputIt first, InputIt last) {
        size = capacity = std::distance(first, last);
        data = new T[capacity];
        
        std::copy(first, last, data);
        
        std::cout << "Iterator range constructor\n";
    }
    
    ~Container() {
        delete[] data;
    }
    
    size_t getCapacity() const { return capacity; }
    size_t getSize() const { return size; }
    
    T& operator[](size_t index) { return data[index]; }
    const T& operator[](size_t index) const { return data[index]; }
};

// 使用模板构造函数
void demonstrateTemplateConstructor() {
    Container<int> intContainer(5);
    intContainer[0] = 1;
    intContainer[1] = 2;
    
    // 使用模板转换构造函数
    Container<double> doubleContainer(intContainer);  // int -> double
    
    // 使用迭代器范围构造函数
    std::vector<std::string> vec = {"Hello", "World", "Template"};
    Container<std::string> strContainer(vec.begin(), vec.end());
    
    // 从数组构造
    int arr[] = {10, 20, 30, 40};
    Container<int> arrContainer(std::begin(arr), std::end(arr));
}

2.4 显式默认构造函数(= default)(C++11)

显式要求编译器生成默认实现。

复制代码
class ModernClass {
private:
    std::string name;
    int id;
    std::vector<double> values;
    
public:
    // 显式默认构造函数
    ModernClass() = default;
    
    // 参数化构造函数
    ModernClass(const std::string& n, int i) : name(n), id(i) {}
    
    // 显式默认拷贝构造函数
    ModernClass(const ModernClass&) = default;
    
    // 显式默认移动构造函数
    ModernClass(ModernClass&&) = default;
    
    // 显式默认析构函数
    ~ModernClass() = default;
    
    // 显式默认拷贝赋值运算符
    ModernClass& operator=(const ModernClass&) = default;
    
    // 显式默认移动赋值运算符
    ModernClass& operator=(ModernClass&&) = default;
    
    // 删除特定函数
    ModernClass(int) = delete;  // 禁止从int构造
    
    void display() const {
        std::cout << "Name: " << name << ", ID: " << id 
                  << ", Values count: " << values.size() << "\n";
    }
};

// 对比传统写法
class TraditionalClass {
private:
    std::string name;
    int id;
    std::vector<double> values;
    
public:
    // 传统写法:需要手动实现所有特殊成员函数
    TraditionalClass() {}  // 空实现
    
    TraditionalClass(const TraditionalClass& other) 
        : name(other.name), id(other.id), values(other.values) {}
    
    TraditionalClass(TraditionalClass&& other) noexcept
        : name(std::move(other.name)), id(other.id), 
          values(std::move(other.values)) {
        other.id = 0;
    }
    
    ~TraditionalClass() {}  // 空析构函数
    
    TraditionalClass& operator=(const TraditionalClass& other) {
        if (this != &other) {
            name = other.name;
            id = other.id;
            values = other.values;
        }
        return *this;
    }
    
    TraditionalClass& operator=(TraditionalClass&& other) noexcept {
        if (this != &other) {
            name = std::move(other.name);
            id = other.id;
            values = std::move(other.values);
            other.id = 0;
        }
        return *this;
    }
};

2.5 显式删除构造函数(= delete)(C++11)

禁止特定的构造函数。

复制代码
class NonCopyable {
private:
    int* resource;
    
public:
    NonCopyable(int value = 0) : resource(new int(value)) {
        std::cout << "NonCopyable constructor: " << value << "\n";
    }
    
    // 删除拷贝构造函数 - 禁止拷贝
    NonCopyable(const NonCopyable&) = delete;
    
    // 删除拷贝赋值运算符
    NonCopyable& operator=(const NonCopyable&) = delete;
    
    // 允许移动
    NonCopyable(NonCopyable&& other) noexcept 
        : resource(other.resource) {
        other.resource = nullptr;
        std::cout << "NonCopyable move constructor\n";
    }
    
    NonCopyable& operator=(NonCopyable&& other) noexcept {
        if (this != &other) {
            delete resource;
            resource = other.resource;
            other.resource = nullptr;
        }
        return *this;
    }
    
    ~NonCopyable() {
        delete resource;
    }
    
    int getValue() const {
        return resource ? *resource : -1;
    }
};

class Singleton {
private:
    static Singleton* instance;
    int data;
    
    // 私有构造函数 - 禁止外部创建
    Singleton() : data(0) {}
    
    // 删除拷贝和移动构造函数
    Singleton(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton& operator=(Singleton&&) = delete;
    
public:
    static Singleton& getInstance() {
        if (!instance) {
            instance = new Singleton();
        }
        return *instance;
    }
    
    void setData(int val) { data = val; }
    int getData() const { return data; }
    
    // 注意:需要单独实现清理逻辑
    static void destroy() {
        delete instance;
        instance = nullptr;
    }
};

// 使用
void demonstrateDeletedConstructors() {
    NonCopyable nc1(42);
    // NonCopyable nc2 = nc1;  // ❌ 错误:拷贝构造函数被删除
    // nc2 = nc1;              // ❌ 错误:拷贝赋值被删除
    
    NonCopyable nc3 = std::move(nc1);  // ✅ 允许移动
    
    Singleton& s1 = Singleton::getInstance();
    // Singleton s2 = s1;      // ❌ 错误:拷贝构造函数被删除
    // Singleton s3;           // ❌ 错误:构造函数私有
}

三、构造函数的特殊特性

3.1 初始化列表(Initializer List)

在构造函数体执行前初始化成员。

复制代码
class InitializationDemo {
private:
    const int constMember;      // 必须在初始化列表初始化
    int& refMember;             // 必须在初始化列表初始化
    int normalMember;
    std::string strMember;
    std::vector<int> vecMember;
    
public:
    // 正确的初始化列表
    InitializationDemo(int x, int& ref, const std::string& str)
        : constMember(x),         // 常量成员
          refMember(ref),         // 引用成员
          normalMember(0),        // 普通成员
          strMember(str),         // 类类型成员
          vecMember{1, 2, 3, 4} { // 使用初始化列表初始化vector
        // 构造函数体
        normalMember = 10;  // 可以在构造函数体中赋值
        
        // constMember = 20;  // ❌ 错误:常量成员不能在构造函数体中赋值
        // refMember = ref;   // ❌ 错误:引用必须在初始化列表初始化
    }
    
    // 初始化顺序取决于成员声明顺序,而不是初始化列表顺序
    class OrderMatters {
        int a;
        int b;
        
    public:
        // 危险:初始化顺序是a先于b,但列表中是b先于a
        OrderMatters(int val) : b(val), a(b + 1) {  // a(b+1)先执行,但b未初始化!
            std::cout << "a = " << a << ", b = " << b << "\n";
        }
    };
    
    void display() const {
        std::cout << "constMember: " << constMember 
                  << ", refMember: " << refMember
                  << ", normalMember: " << normalMember
                  << ", strMember: " << strMember
                  << ", vec size: " << vecMember.size() << "\n";
    }
};

3.2 noexcept 构造函数

声明构造函数不会抛出异常。

复制代码
class NoThrowClass {
private:
    std::unique_ptr<int[]> data;
    size_t size;
    
public:
    // noexcept构造函数 - 承诺不抛出异常
    NoThrowClass(size_t n) noexcept 
        : data(std::make_unique<int[]>(n)), size(n) {
        // 这里不能抛出异常,否则程序会调用std::terminate
        std::fill(data.get(), data.get() + size, 0);
    }
    
    // 移动构造函数也应该是noexcept
    NoThrowClass(NoThrowClass&& other) noexcept 
        : data(std::move(other.data)), size(other.size) {
        other.size = 0;
    }
    
    // noexcept的重要性:标准库容器在重新分配内存时会使用移动
    // 如果移动构造函数不是noexcept,则会使用拷贝
    
    // 标记可能抛出异常的构造函数
    NoThrowClass(const std::string& filename) 
        : data(nullptr), size(0) {
        // 文件操作可能抛出异常
        std::ifstream file(filename);
        if (!file) {
            throw std::runtime_error("Cannot open file");
        }
        // ... 读取数据
    }
};

// 使用noexcept构造函数
void demonstrateNoexcept() {
    std::vector<NoThrowClass> objects;
    
    // 由于移动构造函数是noexcept,vector重新分配时会使用移动
    for (int i = 0; i < 100; ++i) {
        objects.emplace_back(100);  // 高效移动,不会拷贝
    }
}

3.3 私有/受保护构造函数

控制对象的创建方式。

复制代码
class FactoryPattern {
private:
    int id;
    std::string type;
    
    // 私有构造函数 - 只能通过工厂方法创建
    FactoryPattern(int i, const std::string& t) : id(i), type(t) {}
    
public:
    // 工厂方法
    static std::unique_ptr<FactoryPattern> createObjectA(int id) {
        return std::make_unique<FactoryPattern>(id, "TypeA");
    }
    
    static std::shared_ptr<FactoryPattern> createObjectB(int id) {
        return std::make_shared<FactoryPattern>(id, "TypeB");
    }
    
    static FactoryPattern createObjectC(int id) {
        return FactoryPattern(id, "TypeC");  // C++17起保证RVO
    }
    
    // 也可以创建不同子类
    class SubTypeA : public FactoryPattern {
    private:
        SubTypeA(int id) : FactoryPattern(id, "SubTypeA") {}
        
    public:
        static std::unique_ptr<SubTypeA> create(int id) {
            return std::make_unique<SubTypeA>(id);
        }
    };
};

class BuilderPattern {
private:
    std::string name;
    int value;
    double factor;
    
    // 私有构造函数 - 只能通过Builder创建
    BuilderPattern(const std::string& n, int v, double f) 
        : name(n), value(v), factor(f) {}
    
public:
    // Builder类
    class Builder {
    private:
        std::string name;
        int value = 0;
        double factor = 1.0;
        
    public:
        Builder& setName(const std::string& n) {
            name = n;
            return *this;
        }
        
        Builder& setValue(int v) {
            value = v;
            return *this;
        }
        
        Builder& setFactor(double f) {
            factor = f;
            return *this;
        }
        
        BuilderPattern build() {
            if (name.empty()) {
                throw std::invalid_argument("Name cannot be empty");
            }
            return BuilderPattern(name, value, factor);
        }
    };
    
    static Builder createBuilder() {
        return Builder();
    }
    
    void display() const {
        std::cout << "Name: " << name << ", Value: " << value 
                  << ", Factor: " << factor << "\n";
    }
};

// 使用
void demonstratePrivateConstructors() {
    // Factory模式
    auto obj1 = FactoryPattern::createObjectA(1);
    auto obj2 = FactoryPattern::createObjectB(2);
    auto obj3 = FactoryPattern::createObjectC(3);
    
    auto subObj = FactoryPattern::SubTypeA::create(4);
    
    // Builder模式
    auto builder = BuilderPattern::createBuilder();
    auto builtObj = builder.setName("Test")
                           .setValue(100)
                           .setFactor(2.5)
                           .build();
    builtObj.display();
}

四、构造函数的高级应用

4.1 完美转发构造函数

复制代码
template<typename T>
class Wrapper {
private:
    T wrappedObject;
    
public:
    // 完美转发构造函数
    template<typename... Args>
    explicit Wrapper(Args&&... args) 
        : wrappedObject(std::forward<Args>(args)...) {
        std::cout << "Wrapper perfect-forwarding constructor\n";
    }
    
    // 拷贝构造函数(需要单独定义,否则模板会覆盖)
    Wrapper(const Wrapper& other) 
        : wrappedObject(other.wrappedObject) {
        std::cout << "Wrapper copy constructor\n";
    }
    
    // 移动构造函数
    Wrapper(Wrapper&& other) noexcept 
        : wrappedObject(std::move(other.wrappedObject)) {
        std::cout << "Wrapper move constructor\n";
    }
    
    const T& get() const { return wrappedObject; }
    T& get() { return wrappedObject; }
};

// 使用完美转发
void demonstratePerfectForwarding() {
    // 各种构造方式都能正确转发
    Wrapper<std::string> ws1("Hello");        // 从const char*构造
    Wrapper<std::string> ws2(5, 'A');         // 从count和char构造
    Wrapper<std::vector<int>> wv1{1, 2, 3, 4}; // 初始化列表
    Wrapper<std::vector<int>> wv2(10, 42);     // 从count和value构造
    
    // 自定义类型
    class ComplexType {
    public:
        ComplexType(int a, double b, const std::string& c) {
            std::cout << "ComplexType constructor\n";
        }
    };
    
    Wrapper<ComplexType> wc(42, 3.14, "test");  // 完美转发多个参数
}

4.2 SFINAE 约束的构造函数

复制代码
template<typename T>
class SmartContainer {
private:
    std::vector<T> data;
    
public:
    // SFINAE:只有T可默认构造时才启用此构造函数
    template<typename U = T, 
             typename = std::enable_if_t<std::is_default_constructible_v<U>>>
    SmartContainer(size_t size) : data(size) {
        std::cout << "Default value constructor, size: " << size << "\n";
    }
    
    // 只有T可拷贝构造时才启用
    template<typename U = T,
             typename = std::enable_if_t<std::is_copy_constructible_v<U>>>
    SmartContainer(size_t size, const T& value) : data(size, value) {
        std::cout << "Fill constructor, size: " << size << "\n";
    }
    
    // 只有T可从迭代器构造时才启用
    template<typename InputIt,
             typename = std::enable_if_t<
                 std::is_constructible_v<T, 
                     typename std::iterator_traits<InputIt>::value_type>>>
    SmartContainer(InputIt first, InputIt last) : data(first, last) {
        std::cout << "Iterator range constructor\n";
    }
    
    // C++20概念(更简洁)
    /*
    SmartContainer(size_t size) requires std::default_initializable<T>
        : data(size) {}
    
    SmartContainer(size_t size, const T& value) requires std::copyable<T>
        : data(size, value) {}
    
    template<std::input_iterator InputIt>
    SmartContainer(InputIt first, InputIt last) : data(first, last) {}
    */
};

// 使用SFINAE构造函数
void demonstrateSFINAE() {
    // 对于可默认构造的类型
    SmartContainer<int> sci1(10);           // 调用默认值构造函数
    SmartContainer<int> sci2(10, 42);       // 调用填充构造函数
    
    // 对于不可默认构造的类型
    class NoDefault {
    public:
        NoDefault() = delete;
        NoDefault(int) {}
    };
    
    SmartContainer<NoDefault> scn1(10, NoDefault(42));  // OK:填充构造
    // SmartContainer<NoDefault> scn2(10);  // ❌ 错误:没有默认构造函数
}

五、构造函数调用顺序总结

复制代码
class Base {
public:
    Base() { std::cout << "Base constructor\n"; }
    virtual ~Base() { std::cout << "Base destructor\n"; }
};

class Member {
public:
    Member() { std::cout << "Member constructor\n"; }
    ~Member() { std::cout << "Member destructor\n"; }
};

class Derived : public Base {
private:
    Member member;
    int value;
    
public:
    // 构造顺序:
    // 1. 基类构造函数
    // 2. 成员变量构造函数(按声明顺序)
    // 3. 派生类构造函数体
    Derived(int v) : Base(), value(v) {  // 初始化列表顺序不影响实际顺序
        std::cout << "Derived constructor, value = " << value << "\n";
    }
    
    // 析构顺序(相反):
    // 1. 派生类析构函数体
    // 2. 成员变量析构函数(按声明顺序的逆序)
    // 3. 基类析构函数
    ~Derived() {
        std::cout << "Derived destructor\n";
    }
};

// 多重继承
class Base1 {
public:
    Base1() { std::cout << "Base1 constructor\n"; }
};

class Base2 {
public:
    Base2() { std::cout << "Base2 constructor\n"; }
};

class MultipleDerived : public Base1, public Base2 {
public:
    // 构造顺序:
    // 1. Base1构造函数
    // 2. Base2构造函数
    // 3. MultipleDerived构造函数体
    MultipleDerived() {
        std::cout << "MultipleDerived constructor\n";
    }
};

// 虚继承
class VirtualBase {
public:
    VirtualBase() { std::cout << "VirtualBase constructor\n"; }
};

class VirtualDerived1 : virtual public VirtualBase {
public:
    VirtualDerived1() { std::cout << "VirtualDerived1 constructor\n"; }
};

class VirtualDerived2 : virtual public VirtualBase {
public:
    VirtualDerived2() { std::cout << "VirtualDerived2 constructor\n"; }
};

class DiamondDerived : public VirtualDerived1, public VirtualDerived2 {
public:
    // 虚基类只构造一次
    // 构造顺序:
    // 1. VirtualBase构造函数(虚基类优先)
    // 2. VirtualDerived1构造函数
    // 3. VirtualDerived2构造函数  
    // 4. DiamondDerived构造函数体
    DiamondDerived() {
        std::cout << "DiamondDerived constructor\n";
    }
};

六、最佳实践总结

  1. 使用初始化列表初始化所有成员,特别是常量和引用

  2. 按声明顺序编写初始化列表

  3. 对于简单类 使用 = default

  4. 对于资源管理类定义拷贝/移动构造函数和赋值运算符

  5. 使用 explicit 防止意外的隐式转换

  6. 移动构造函数 应该标记为 noexcept

  7. 单参数构造函数 考虑是否需要 explicit

  8. 委托构造函数避免代码重复

  9. 模板构造函数注意不要隐藏拷贝/移动构造函数

  10. 考虑使用工厂模式而不是复杂的构造函数

构造函数是C++对象生命周期的起点,合理使用各种构造函数可以提高代码的健壮性、安全性和性能。

相关推荐
小此方2 小时前
Re:从零开始学C++(五)类和对象·第二篇:构造函数与析构函数
开发语言·c++
秦苒&2 小时前
【C语言】详解数据类型和变量(二):三种操作符(算数、赋值、单目)及printf
c语言·开发语言·c++·c#
无限进步_2 小时前
【C语言&数据结构】有效的括号:栈数据结构的经典应用
c语言·开发语言·数据结构·c++·git·github·visual studio
是喵斯特ya2 小时前
python开发web暴力破解工具(进阶篇 包含验证码识别和token的处理)
开发语言·python·web安全
零K沁雪2 小时前
multipart-parser-c 使用方式
c语言·开发语言
chilavert3182 小时前
技术演进中的开发沉思-260 Ajax:核心动画
开发语言·javascript·ajax
云中飞鸿2 小时前
为什么有out参数存在?
开发语言·c#
飞天遇见妞2 小时前
C/C++中宏定义的使用
c语言·开发语言·c++