C++对象构造、赋值、拷贝与析构详解

发布于:2024-12-06 ⋅ 阅读:(26) ⋅ 点赞:(0)

C++对象构造、赋值、拷贝与析构详解


1. 构造函数

构造函数是用于初始化对象的函数,在创建对象时自动调用。

特点
  1. 名称与类名相同,无返回值。
  2. 可以重载,允许多个构造函数。
  3. 可以有默认值,也可以无参数(默认构造函数)。
代码示例
class Test {
public:
    int x, y;

    // 默认构造函数
    Test() : x(0), y(0) {
        cout << "Default Constructor called" << endl;
    }

    // 带参数的构造函数
    Test(int a, int b) : x(a), y(b) {
        cout << "Parameterized Constructor called" << endl;
    }
};
int main() {
    Test t1;            // 调用默认构造函数
    Test t2(10, 20);    // 调用带参数的构造函数
    return 0;
}
输出
Default Constructor called
Parameterized Constructor called

2. 拷贝构造函数

用于通过一个已存在的对象创建一个新对象。

特点
  1. 默认的拷贝构造函数执行浅拷贝(简单复制数据成员的值)。
  2. 如果类包含指针或动态分配的资源,建议定义深拷贝
代码示例(深拷贝实现)
class Test {
private:
    int* data;

public:
    // 带参数构造函数
    Test(int value) {
        data = new int(value);
        cout << "Constructor called for value: " << *data << endl;
    }

    // 拷贝构造函数
    Test(const Test& obj) {
        data = new int(*obj.data);  // 深拷贝
        cout << "Copy Constructor called" << endl;
    }

    // 析构函数
    ~Test() {
        delete data;
        cout << "Destructor called" << endl;
    }
};
int main() {
    Test t1(10);        // 调用构造函数
    Test t2 = t1;       // 调用拷贝构造函数
    return 0;
}
输出
Constructor called for value: 10
Copy Constructor called
Destructor called
Destructor called

3. 赋值操作符重载

用于将一个对象的值赋给另一个已存在的对象。

区别
  • 拷贝构造函数:在创建新对象时调用。
  • 赋值操作符:在对象已经存在时调用。
代码示例
class Test {
private:
    int* data;

public:
    // 构造函数
    Test(int value) {
        data = new int(value);
        cout << "Constructor called for value: " << *data << endl;
    }

    // 拷贝构造函数
    Test(const Test& obj) {
        data = new int(*obj.data);
        cout << "Copy Constructor called" << endl;
    }

    // 赋值操作符重载
    Test& operator=(const Test& obj) {
        if (this == &obj) return *this; // 防止自赋值
        delete data;                    // 释放旧资源
        data = new int(*obj.data);      // 深拷贝
        cout << "Assignment Operator called" << endl;
        return *this;
    }

    // 析构函数
    ~Test() {
        delete data;
        cout << "Destructor called" << endl;
    }
};
int main() {
    Test t1(10);          // 调用构造函数
    Test t2(20);          // 调用构造函数
    t2 = t1;              // 调用赋值操作符
    return 0;
}
输出
Constructor called for value: 10
Constructor called for value: 20
Assignment Operator called
Destructor called
Destructor called

4. 静态对象

静态对象在程序生命周期内只初始化一次,其析构函数会在程序结束时调用。

代码示例
class Test {
public:
    Test() { cout << "Constructor called" << endl; }
    ~Test() { cout << "Destructor called" << endl; }
};
int main() {
    static Test t;    // 静态对象
    cout << "Main function ends" << endl;
    return 0;
}
输出
Constructor called
Main function ends
Destructor called

5. 动态分配与内存管理

动态分配允许在运行时分配内存,但需手动释放。

代码示例
class Test {
public:
    Test() { cout << "Constructor called" << endl; }
    ~Test() { cout << "Destructor called" << endl; }
};
int main() {
    Test* obj = new Test();  // 动态分配单个对象
    delete obj;              // 释放单个对象

    Test* arr = new Test[2]; // 动态分配对象数组
    delete[] arr;            // 释放对象数组
    return 0;
}
输出
Constructor called
Constructor called
Constructor called
Destructor called
Destructor called
Destructor called

6. 临时对象与优化
  • 临时对象
    • 在表达式中创建的对象,生命周期短。
    • 常用于函数返回值或强制类型转换。
代码示例
class Test {
public:
    Test(int value) { cout << "Constructor called for value: " << value << endl; }
    ~Test() { cout << "Destructor called" << endl; }
};
int main() {
    Test t1 = Test(10); // 临时对象
    return 0;
}
输出
Constructor called for value: 10
Destructor called
  • 优化临时对象
    1. 使用引用传递避免拷贝:
      void func(const Test& obj);
      
    2. 使用移动语义优化临时对象(C++11):
      Test(Test&& obj) noexcept { /* 转移资源 */ }
      

函数调用中的对象行为
  • 示例
    Test getObject(Test t) {
        Test tmp(t.data);
        return tmp;
    }
    Test t2 = getObject(t1);
    
  • 背后调用顺序
    1. t1 构造。
    2. 实参传递调用拷贝构造。
    3. 局部对象tmp调用构造函数。
    4. 返回临时对象调用拷贝构造。
    5. 临时对象赋值给t2调用赋值运算符。
    6. 局部对象和临时对象析构。

注意事项
  1. 禁止返回局部对象的指针或引用
    • 局部对象在函数结束时被销毁,返回其地址会导致悬空指针。
  2. 优化建议
    • 使用引用传递避免拷贝。
    • 避免不必要的临时对象生成。

7. 完整示例

以下是一个综合示例,展示对象的构造、拷贝、赋值、动态分配与析构:

#include <iostream>
using namespace std;

class Test {
private:
    int* data;

public:
    // 构造函数
    Test(int value = 0) {
        data = new int(value);
        cout << "Constructor called for value: " << *data << endl;
    }

    // 拷贝构造函数
    Test(const Test& obj) {
        data = new int(*obj.data);
        cout << "Copy Constructor called" << endl;
    }

    // 赋值操作符
    Test& operator=(const Test& obj) {
        if (this == &obj) return *this; // 防止自赋值
        delete data;
        data = new int(*obj.data);
        cout << "Assignment Operator called" << endl;
        return *this;
    }

    // 析构函数
    ~Test() {
        delete data;
        cout << "Destructor called" << endl;
    }
};

int main() {
    Test t1(10);           // 构造函数
    Test t2 = t1;          // 拷贝构造函数
    Test t3;               // 默认构造函数
    t3 = t1;               // 赋值操作符
    Test* p = new Test(20); // 动态分配
    delete p;              // 释放动态分配的内存
    return 0;
}
输出
Constructor called for value: 10
Copy Constructor called
Constructor called for value: 0
Assignment Operator called
Constructor called for value: 20
Destructor called
Destructor called
Destructor called
Destructor called

8. 总结
  1. 构造函数:用于对象初始化,可以有参数或默认值。
  2. 拷贝构造函数:用于复制对象,推荐实现深拷贝。
  3. 赋值操作符:对象赋值时调用,需处理自赋值和旧资源释放。
  4. 析构函数:对象生命周期结束时自动释放资源,避免内存泄漏。
  5. 动态分配:需要deletedelete[]手动释放内存。
  6. 临时对象:生命周期短,尽量优化避免不必要的生成。

网站公告

今日签到

点亮在社区的每一天
去签到