zoukankan      html  css  js  c++  java
  • 深拷贝与浅拷贝,还有一道比较好的面试题

    转自如下:

    https://blog.csdn.net/zzwdkxx/article/details/53409803

    ==================================================

    1. 深拷贝和浅拷贝(拷贝构造函数的使用)

    有时候需要自己定义拷贝构造函数,以避免浅拷贝问题。

    在什么情况下需要用户自己定义拷贝构造函数:

    一般情况下,当类中成员有指针变量、类中有动态内存分配时常常需要用户自己定义拷贝构造函数。

    在什么情况下系统会调用拷贝构造函数:(三种情况)

    (1)用类的一个对象去初始化另一个对象时

    (2)当函数的形参是类的对象时(也就是值传递时),如果是引用传递则不会调用

    (3)当函数的返回值是类的对象或引用时

    简单示例:

    #include <iostream>  
    using namespace std;  
      
    class A  
    {  
    private:  
        int a;  
    public:  
        A(int i){a=i;}  //内联的构造函数  
        A(A &aa);  
        int geta(){return a;}  
    };  
      
    A::A(A &aa)     //拷贝构造函数  
    {  
        a=aa.a;  
        cout<<"拷贝构造函数执行!"<<endl;  
    }  
      
    int get_a(A aa)     //参数是对象,是值传递,会调用拷贝构造函数  
    {  
        return aa.geta();  
    }  
      
    int get_a_1(A &aa)  //如果参数是引用类型,本身就是引用传递,所以不会调用拷贝构造函数  
    {  
        return aa.geta();  
    }  
      
    A get_A()       //返回值是对象类型,会调用拷贝构造函数。会调用拷贝构造函数,因为函数体内生成的对象aa是临时的,离开这个函数就消失了。所有会调用拷贝构造函数复制一份。  
    {  
        A aa(1);  
        return aa;  
    }  
      
    A& get_A_1()    //会调用拷贝构造函数,因为函数体内生成的对象aa是临时的,离开这个函数就消失了。所有会调用拷贝构造函数复制一份。  
    {  
        A aa(1);  
        return aa;  
    }  
      
    int _tmain(int argc, _TCHAR* argv[])  
    {  
        A a1(1);  
        A b1(a1);           //用a1初始化b1,调用拷贝构造函数  
        A c1=a1;            //用a1初始化c1,调用拷贝构造函数  
      
        int i=get_a(a1);        //函数形参是类的对象,调用拷贝构造函数  
        int j=get_a_1(a1);      //函数形参类型是引用,不调用拷贝构造函数  
      
        A d1=get_A();       //调用拷贝构造函数  
        A e1=get_A_1();     //调用拷贝构造函数  
      
        return 0;  
    }  


     

    附:一个面试试题

    修改下面程序中的错误:

    #include <iostream>  
    using namespace std;  
      
    class NameStr  
    {  
    private:  
        char *m_pName;  
        char *m_pData;  
    public:  
        NameStr()  
        {  
            static const char s_szDefaultName[]="Default name";  
            static const char s_szDefaultStr[]="Default string";  
            strcpy(m_pName,s_szDefaultName);  
            strcpy(m_pData,s_szDefaultStr);  
        }  
        ~NamedStr(){}  
        NameStr(const char* pName,const char* pData)  
        {  
            m_pData=new char[strlen(pData)];  
            m_pName=new char[strlen(pData)];  
        }  
      
        void Print()  
        {  
            cout<<"Name:"<<m_pName<<endl;  
            cout<<"String:"<<m_pData<<endl;  
        }  
    };  
      
    int _tmain(int argc, _TCHAR* argv[])  
    {  
        NameStr* pDefNss=NULL;  
      
        pDefNss=new NameStr[10];  
        NameStr ns("hello","world");  
      
        delete pDefNss;  
      
        return 0;  
    }  

    分析:

    1. 第14、15行,strcpy(m_pName,s_szDefaultName) 对未分配内存空间的字符指针赋值会出现异常。

    2. 第20行、21行,m_pData=new char[strlen(pData)] 应该为m_pData=new char[strlen(pData)+1] ,并且应该为最后一个字符赋值为''。

    3. 析构函数中,应该处理字符指针内存空间的释放。

    4. 因为类的成员变量中有指针变量,因此应该编写类的拷贝构造函数和赋值函数,防止浅拷贝。

    5. pDefNss是一个对象数组,delete时应该是delete [ ]pDefNss。

    比较规范的代码如下:

    #include <iostream>  
    using namespace std;  
      
    //NameStr类的声明  
    class NameStr  
    {  
    private:  
        char *m_pName;  
        char *m_pData;  
    public:  
        NameStr();      //默认拷贝构造函数  
      
        ~NameStr(); //析构函数声明  
      
        NameStr(const char* pName,const char* pData);   //带参构造函数的声明  
      
        NameStr(const NameStr& temp);   //拷贝构造函数的声明  
      
        NameStr& operator= (const NameStr& temp);   //重载=运算符  
      
        void Print();   //输出对象内容  
    };  
      
    //默认构造函数的实现  
    NameStr::NameStr()    
    {  
        static const char s_szDefaultName[]="Default name";  
        static const char s_szDefaultStr[]="Default string";  
      
        m_pData=new char[strlen(s_szDefaultStr)+1];     //不能为为分配内存空间的字符指针赋值  
        m_pName=new char[strlen(s_szDefaultName)+1];  
      
        strcpy(m_pName,s_szDefaultName);        //更规范的方式是使用strncpy函数进行拷贝  
        m_pName[strlen(s_szDefaultName)]='';  
        strcpy(m_pData,s_szDefaultStr);  
        m_pData[strlen(s_szDefaultStr)]='';  
    }  
      
    //析构函数的实现  
    NameStr::~NameStr()  
    {  
        delete []m_pData;  
        delete []m_pName;  
    }  
      
    //带参构造函数的实现  
    NameStr::NameStr(const char* pName,const char* pData)  
    {  
        m_pData=new char[strlen(pData)+1];      //开辟内存空间  
        m_pName=new char[strlen(pName)+1];  
      
        strcpy(m_pData,pData);  
        m_pData[strlen(pData)]='';  
        strcpy(m_pName,pName);  
        m_pName[strlen(pName)]='';  
    }  
      
    //拷贝构造函数的实现  
    NameStr::NameStr(const NameStr& temp)  
    {  
        m_pData=new char[strlen(temp.m_pData)+1];         
        m_pName=new char[strlen(temp.m_pName)+1];  
      
        strcpy(m_pData,temp.m_pData);  
        m_pData[strlen(temp.m_pData)]='';  
        strcpy(m_pName,temp.m_pName);  
        m_pName[strlen(temp.m_pName)]='';  
    }  
      
    //重载=运算符的实现  
    NameStr& NameStr::operator=(const NameStr& temp)      
    {  
        //首先要进行检查,防止自身复制  
        if(&temp==this) //this是一个指针,表示本对象的地址。&temp是temp对象的指针。  
        {  
            return *this;  
        }  
      
        //释放原有的内存空间  
        delete []m_pData;  
        delete []m_pName;  
      
        //分配新的内存空间  
        m_pData=new char[strlen(temp.m_pData)+1];         
        m_pName=new char[strlen(temp.m_pName)+1];  
      
        //进行拷贝  
        strcpy(m_pData,temp.m_pData);  
        m_pData[strlen(temp.m_pData)]='';  
        strcpy(m_pName,temp.m_pName);  
        m_pName[strlen(temp.m_pName)]='';  
      
        //返回本对象的引用  
        return *this;  
    }  
      
    inline void NameStr::Print()  
    {  
        cout<<"Name:"<<m_pName<<endl;  
        cout<<"String:"<<m_pData<<endl;  
    }  
      
    //程序入口  
    int _tmain(int argc, _TCHAR* argv[])  
    {  
        NameStr* pDefNss=NULL;  
      
        pDefNss=new NameStr[3];  
        NameStr ns("hello","world");  
      
        delete []pDefNss;  
      
        NameStr ns1=ns;  
      
        return 0;  
    }  
  • 相关阅读:
    java web项目打包.war格式
    version 1.4.2-04 of the jvm is not suitable for thi
    Sugarcrm Email Integration
    sharepoint 2010 masterpage中必须的Content PlaceHolder
    微信开放平台
    Plan for caching and performance in SharePoint Server 2013
    使用自定义任务审批字段创建 SharePoint 顺序工作流
    Technical diagrams for SharePoint 2013
    To get TaskID's Integer ID value from the GUID in SharePoint workflow
    how to get sharepoint lookup value
  • 原文地址:https://www.cnblogs.com/WHUT-Simon/p/11736217.html
Copyright © 2011-2022 走看看