Board logo

标题: C++构造函数详解及显式调用构造函数(2) [打印本页]

作者: yuyang911220    时间: 2017-4-21 21:03     标题: C++构造函数详解及显式调用构造函数(2)

四、附录(浅拷贝与深拷贝)
       上面提到,如果没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的 值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针 时则会导致两次重复delete而出错。下面是示例:
  【浅拷贝与深拷贝】
  #include <iostream.h>
#include <string.h>
class Person
{
public :
         // 构造函数
        Person(char * pN)
        {
              cout << "一般构造函数被调用 !\n";
              m_pName = new char[strlen(pN) + 1];
              //在堆中开辟一个内存块存放pN所指的字符串
              if(m_pName != NULL)
              {
                 //如果m_pName不是空指针,则把形参指针pN所指的字符串复制给它
                   strcpy(m_pName ,pN);
              }
        }        
        
        // 系统创建的默认复制构造函数,只做位模式拷贝
        Person(Person & p)   
        {
                  //使两个字符串指针指向同一地址位置         
                 m_pName = p.m_pName;         
        }
         ~Person( )
        {
                delete m_pName;
        }
  private :

        char * m_pName;
};

void main( )
{
        Person man("lujun");
        Person woman(man);
        
        // 结果导致   man 和    woman 的指针都指向了同一个地址
        
        // 函数结束析构时
        // 同一个地址被delete两次
}
// 下面自己设计复制构造函数,实现“深拷贝”,即不让指针指向同一地址,而是重新申请一块内存给新的对象的指针数据成员
Person(Person & chs);
{
         // 用运算符new为新对象的指针数据成员分配空间
         m_pName=new char[strlen(p.m_pName)+ 1];

         if(m_pName)         
         {
                 // 复制内容
                strcpy(m_pName ,chs.m_pName);
         }
      
        // 则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了
}

参考地址:http://ticktick.blog.51cto.com/823160/194307
下面讨论一个重要问题是:构造函数的显式调用

大家看看下面这段代码的输出结果是什么?这段代码有问题么?

[url=][/url]
[url=][/url]
    #include <iostream>  
    class CTest  
    {
    public:
        CTest()  
        {  
            m_a = 1;  
        }  
        CTest(int b)  
        {  
            m_b = b;  
            CTest();  
        }  
        ~CTest()  
        {}  
        void show  
        {  
            std::cout << m_a << std::endl;  
            std::cout << m_b << std::endl;  
        }  
     private:  
        int m_a;  
        int m_b;  
    };
   void main()  
    {  
        CTest myTest(2);  
        myTest.show();  
    }
[url=][/url]
[url=][/url]

-----------------------------------------------------------
【分析】
-----------------------------------------------------------输出结果中,m_a是一个不确定的值,因为没有被赋初值,m_b 为2
注意下面这段代码
CTest(int b)
{
    m_b = b;
    CTest();
}
在调用CTest()函数时,实际上是创建了一个匿名的临时CTest类对象,CTest()中赋值 m_a = 1 也是对该匿名对象赋值,故我们定义的myTest的m_a其实没有被赋值。说白了,其实构造函数并不像普通函数那样进行一段处理,而是创建了一个对象,并 且对该对象赋初值,所以显式调用构造函数无法实现给私有成员赋值的目的。
这个例子告诉我们以后代码中千万不要出现使用一个构造函数显式调用另外一个构造函数,这样会出现不确定性。其实一些初始化的代码可以写在一个单独的init函数中,然后每一个构造函数都调用一下该初始化函数就行了。
    在此,顺便再提出另外一个问题以供思考:
    CTest *p = NULL;  
    void func()  
    {     
        p = new CTest();  
    }

代码右边显示调用CTest(),是否依然会产生一个匿名的临时对象a,然后将该匿名的临时对象a的地址赋给指针p? 如果是这样的话,出了func函数后,临时对象a是否会被析构? 那指针p不成为了野指针了?你能解释这个问题么?




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0