【C/C++基础进阶系列】C/C++ 对象模型 -- 对象构造语义(二)
发布日期:2021-05-07 20:53:21 浏览次数:18 分类:精选文章

本文共 2660 字,大约阅读时间需要 8 分钟。

C++ 对象模型:拷贝构造函数的深度探讨

1. 拷贝构造函数的合成生成

在C++中,编译器会自动为类生成拷贝构造函数,但只有在特定情况下才会生效。以下是两种关键情况:

  • 如果类没有定义拷贝构造函数。
  • 类中包含一个类类型成员变量,该类有定义拷贝构造函数。
  • 例如:

    #include 
    using namespace std;class A {public: int m_test;};int main() { A mya1; mya1.m_test = 15; A mya2 = mya1; return 0;}

    此处,编译器会自动生成拷贝构造函数,负责复制基本数据类型的成员变量值。

    当类包含复合对象(如ASon类和CTB类成员变量)时,编译器会递归复制每个成员变量的值。例如:

    class ASon {public:    int m_testson;};class A {public:    int m_test;    ASon asubobj;    CTB m_ctb;};int main() {    A mya1;    mya1.m_test = 15;    mya1.asubobj.m_testson = 120;    A mya2 = mya1;    return 0;}

    编译器会为A类生成拷贝构造函数,调用CTB类的拷贝构造函数。

    2. 拷贝构造函数的调用时机与作用

    拷贝构造函数在以下情况下被调用:

    • 当使用=操作符进行拷贝赋值时。
    • 当使用newdelete操作符进行内存管理时。

    例如:

    class X {public:    int m_i;    int* p_mi;    X() {        m_i = 0;        p_mi = new int(100);        cout << "X类的构造函数被调用" << endl;    }    X(const X& tmp) {        m_i = tmp.m_i;        cout << "X类的拷贝构造函数被调用" << endl;    }    ~X() {        delete p_mi;        cout << "X类的析构函数被调用" << endl;    }    X(int value) : m_i(value) {        p_mi = new int(100);        cout << "X类的X(int)构造函数被调用" << endl;    }};int main() {    X x0;    x0.m_i = 150;    X x1(x0);    cout << x1.m_i << endl;    return 0;}

    输出:

    150

    3. 深拷贝与浅拷贝

    浅拷贝仅复制对象的值,而不复制指向外部资源(如内存)的指针。深拷贝则确保所有嵌套对象也被复制。

    例如:

    class X {public:    int m_i;    int* p_mi;    X() {        m_i = 0;        p_mi = new int(100);        cout << "X类的构造函数被调用" << endl;    }    ~X() {        delete p_mi;        cout << "X类的析构函数被调用" << endl;    }    X(int value) : m_i(value) {        p_mi = new int(100);        cout << "X类的X(int)构造函数被调用" << endl;    }};int main() {    X x0;    x0.m_i = 150;    X x1(x0);    // 浅拷贝:x1.m_i = 150    cout << x1.m_i << endl;    return 0;}

    此处,x1和x0的p_mi指向同一块内存。如果x0被释放,x1的p_mi指针将失效,导致内存泄漏。

    4. 拷贝复制运算符与拷贝构造函数

    默认情况下,C++支持对象的拷贝复制,但在某些情况下(如资源管理),需要自定义拷贝构造函数和拷贝赋值运算符。

    例如:

    #include 
    using namespace std;class A {public: int m_i, m_j; A& operator=(const A& tmp) { m_i = tmp.m_i; m_j = tmp.m_j; cout << "A::operator=(const A&)拷贝赋值运算符执行了" << endl; return *this; } A(const A& tmp) { m_i = tmp.m_i; m_j = tmp.m_j; cout << "A::A(const A&)拷贝构造函数执行了" << endl; } A() { cout << "A::A()缺省构造函数执行了" << endl; }};int main() { A aobj; aobj.m_i = 15; aobj.m_j = 20; A aobj2 = aobj; A aobj3; aobj3.m_i = 13; aobj3.m_j = 16; aobj2 = aobj3; return 0;}

    默认复制行为可以满足基本需求,但在资源管理和异常安全中,自定义拷贝构造函数和拷贝赋值运算符至关重要。

    结论

    通过上述内容,我们可以看到:

  • 拷贝构造函数的合成生成:编译器会根据类的结构自动生成拷贝构造函数,适用于基本数据类型和嵌套对象的复制。
  • 拷贝构造函数的调用时机:在拷贝赋值和内存管理时,拷贝构造函数会被调用以确保对象的正确复制。
  • 深拷贝与浅拷贝的区别:深拷贝确保所有嵌套对象的复制,避免内存泄漏,而浅拷贝仅复制对象本身的值。
  • 拷贝复制运算符的重要性:在资源管理和异常处理中,自定义拷贝构造函数和拷贝赋值运算符可以防止资源泄漏和数据不一致。
  • 上一篇:【C/C++基础进阶系列】C/C++ 对象模型 -- 对象构造语义(三)
    下一篇:【C/C++基础进阶系列】C/C++ 对象模型 -- 对象构造语义(一)

    发表评论

    最新留言

    哈哈,博客排版真的漂亮呢~
    [***.90.31.176]2025年03月24日 00时16分35秒