现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

全面学习C++浅复制

2012-07-12 07:50 工业·编程 ⁄ 共 2617字 ⁄ 字号 暂无评论

一、     什么是浅复制
    我想用一种形象的说法来说明这个问题。这里我的定义是不够严谨的,只是适合于C++的初学者。
   首先明确在C++中复制这个动作在内存中做了些什么?它先得到一个内存区域,然后再把要复制的东西“填进”这个区域。而所谓的“浅复制”并不是这样进行复制的,它仅仅是让一个指针指向要复制的区域。
 
二、     一个关于浅复制的简单例子
这里定义了Inner和Outter两个类。
class Inner
{
      public:
            Inner();
            ~Inner();
      public:
           int min1;
};
 
class Outter
{
      public:
            Outter(int m_1);//让pInner->min1等于min1
            ~Outter();
      public:
            Inner* pInner;
};
Outter::~Outter()
{
      cout<<\"called the Destructors of Outter.\"<<endl;
      delete pInner;
}
其它方法的实现很简单,这里就不写出来了。代码贴在最后面。下面有个问题,如果在一个函数(如main)中我们写了这几行代码,有会什么结果?
void print(Outter mOutter);
int main()
{
     Outter mOut1(20);
   print(mOut1);   
cout<<mOut1.pInner->min1<<endl;
 
    return 0;
}
         print函数并不在那两个类中,它的实现如下:
void print(Outter mOutter)
{
      cout<<\"called print().\"<<endl;
      cout<<mOutter.pInner->min1<<endl;
}
      结果是,print函数结果正常,也就是20。但是,在main打印出的原来那个对象(mOut1)的min1值却变了,成了一个很小的负数,程序也出现异常了。如果去掉print(mOut1)这一行,结果也是20。那么问题就一定是出在print函数中了。可是我们用什么方法传递参数呢?我们是按“值传递”啊!按“理”说,出了这个函数后mOut1.pInner->min1的数据应该不会改变才对,可是事实它就是变了。
“值传递”在这里会为目标对象生成源对象的一个副本,更直接地说就是在内存会分配一个空间,将mOut1的数据复制进来。我们没定义复制构造函数,这时C++编绎器会为我们自动生成一个。但是很不幸,复制的工作没有做“深”,只是表面在让mOutter.pInner = mOut1.pInner,而不是让mOutter.pInner指向一个新开的区域,然后再往里面填相关的数据。所以当mOutter出作用域时,它会自动调用Outter的析构函数。由于我们在析构函数里用了delete pInner(想想为什么要用这个),它当然把所指的内存区域释放掉。所以,在print后我们用cout<<mOut1.pInner->min1<<endl一定得不到正确的结果,而这句之后,main函数退出过程也要调用Outter的析构函数,delete空区域当然不行了,所以就出现异常。 [Page]
三、     问题的解决
  前面我们分析了问题的根源,现在想想应该怎么解决这个问题?这个问题的解决比查出它的原因容易得多。我们只需把没有做“深”的事情做“深”就可以了。既然C++编程器的复制构造函数“不好用”,我们就自己写一个吧。代码如下:
Outter::Outter(const Outter& mOut)
{
    cout<<\"called the Copy Constructors of Outter.\"<<endl;
      pInner = new Inner();//重新分配一个区域,把工作做“深”
      pInner->min1 = mOut.pInner->min1; 
}
加上const是保证mOut的数据在这个函数中不会被修改。
 
 
下面把代码贴上,在VC++2005中能正常运行,其它编绎器我没试过。

#include <iostream>

using namespace std;

class Inner
{
public:
    Inner();
    ~Inner();
public:
    int min1;

};

Inner::Inner()
{
    cout<<"called the Constructors of Inner."<<endl;
}

Inner::~Inner()
{
    cout<<"called the Destructors of Inner."<<endl;
}

class Outter
{
public:
    Outter(int m_1);
    Outter(const Outter& mOut);
~Outter();
public:
    Inner* pInner;
};

Outter::Outter(int m_1)
{
    cout<<"called the Constructors of Outter."<<endl;
        pInner = new Inner;
    pInner->min1 = m_1;
}

Outter::Outter(const Outter& mOut)
{
    cout<<"called the Copy Constructors of Outter."<<endl;
        pInner = new Inner();
    pInner->min1 = mOut.pInner->min1;
}

Outter::~Outter()
{
    cout<<"called the Destructors of Outter."<<endl;
        delete pInner;
}

void print(Outter mOutter)
{
    cout<<"called print()."<<endl;
        cout<<mOutter.pInner->min1<<endl;
}

int main()
{
    Outter mOut1(20);

    print(mOut1);
    cout<<mOut1.pInner->min1<<endl;
    return 0;
}

给我留言

留言无头像?