zoukankan      html  css  js  c++  java
  • 拷贝构造函数中的陷阱

      拷贝构造函数大家都比较熟悉,通俗讲就是传入一个对象,拷贝一份副本。

      不过看似简单的东西,实际不注意的话就会产生问题!

    #include<iostream>
    using namespace std;
    
    class CExample 
    {
    public:
        int a,b,c;
        char *str;
    
    public:
        //构造函数
        CExample(int tb)
        { 
            a = tb;
            b = tb+1;
            c = tb+2;
            str=(char *)malloc(sizeof(char)*10);
            strcpy(str,"123456789");
            cout<<"creat: "<<endl;
        }
    
    
        //析构函数
        ~CExample()
        {
            cout<< "delete: "<<endl;
        }
    
        void Show ()
        {
            cout<<a<<endl;
        }
    
        //拷贝构造
    
        //CExample(const CExample& C)
        //{
        //    str=(char *)malloc(sizeof(char)*10);
        //    strcpy(str,C.str);
        //    cout<<"copy"<<endl;
        //}
    };
    
    //全局函数,传入的是对象
    void g_Fun(CExample C)
    {
        C.a=0;C.b=0;C.b=0;
        strcpy(C.str,"aaabbbccc");
        cout<<"test"<<endl;
    }
    
    int main()
    {
        CExample test(1);
        cout<<"str:"<<test.str<<" a="<<test.a<<" b="<<test.b<<" c="<<test.c<<endl;
        
        g_Fun(test);//传入对象
    
        cout<<"str:"<<test.str<<" a="<<test.a<<" b="<<test.b<<" c="<<test.c<<endl;
        getchar();
        return 0;
    }

    这个结果似乎出乎了我们的预料,作为形式参数 test对象被修改了,同时是test.str的部分被修改了,test的整数成员变量没有被修改!

    咱们先了解一下系统默认的拷贝构造函数,因为类中没有写自己的拷贝构造函数,所以调用的是默认的拷贝构造函数。

    Thinking in c++:对于简单结构,编译器会自动生成一个缺省的,就是位拷贝(bitcopy)。
    对于比较复杂的类型,编译器就会自动生成一个缺省的拷贝构造函数。

    class CExample 
    {
        int a,b,c;
    };

    这就是一个简单结构的类,位拷贝,就是按对象在内存中的二进制进行拷贝,对于不涉及指针等类型的时候,位拷贝是比较不错的拷贝方法。

    但是,要是一个类中有指针类型的时候,如

    class CExample 
    {
        int a,b,c;
        char *str;
    };

    位拷贝就会把指针地址拷贝了一下,话句话说,这里只进行了“浅拷贝”,一旦副本里涉及到指针的操作,必然就会影响到原始对象的成员变量,这就是导致,上面代码中对象的整数变量没被修改(对整数变量的位拷贝其实就是一种“深拷贝”),而str所指的对象被修改的原因。

    那么该如何防止对副本的修改影响原始对象呢?

    答案是用户自定义拷贝构造函数!

        CExample(const CExample& C)
        {
            a=C.a;b=C.b;c=C.b;
            str=(char *)malloc(sizeof(char)*10);
            strcpy(str,C.str);
            cout<<"copy"<<endl;
        }

    这样就可以正确完成拷贝构造的操作了。

    总结:对于简单的数据类型,可以使用系统默认的拷贝构造函数;但对于复杂的数据类型(如指针),其实就是深拷贝和浅拷贝的区别!一般类如果包含指针或引用成员,应该遵守Rule of Three原则。(感谢@24K纯开源

    @24K纯开源 指出的三法则:

    三法则英语rule of threethe Law of The Big ThreeThe Big Three三法则三大定律)在 C++ 程序设计里,它是一个以设计的基本原则而制定的定律,三法则的要求在于,假如类型有明显地定义下列其中一个成员函数,那么程序员必须连其他二个成员函数也一同编写至类型内,亦即下列三个成员函数缺一不可。 [1]:

    参考 http://zh.wikipedia.org/wiki/%E4%B8%89%E6%B3%95%E5%89%87_(C%2B%2B%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88)

  • 相关阅读:
    CMake使用教程
    非常陌生的cmake
    C#绘制立体三维饼状图
    有关C,C++,C#, Java的图形图像处理类库 整理(未完待续)
    Eclipse安装Maven插件报错
    WebLogic11g-常用运维操作
    WebLogic之eclipse安装WebLogic插件
    The server does not support version 3.0 of the J2EE Web module specification
    Project facet Java version 1.8 is not supported解决记录
    Weblogic部署项目三种方式
  • 原文地址:https://www.cnblogs.com/huhuuu/p/3490925.html
Copyright © 2011-2022 走看看