C++学习笔记(一).拷贝构造函数

来源:互联网 发布:mac如何查看java版本 编辑:程序博客网 时间:2024/05/22 04:41
  
在C和C++中,对于内部类型(如:int、float、char等)的普通变量通过传值方式作为函数参数和返回值传递时,直接用位拷贝的方式来实现是没问题的;但是在C++中,对于对象(其类型为我们自定义的类类型),如果通过简单的位拷贝来实现就会有问题,这样不能对类对象进行真正的初始化以维护它的完整性。(可以想:如果类中含有指针的话,如果通过位拷贝,那么新的对象的指针将指向什么内容?它们将与新的内存块相连还是和源对象指向同一块内存呢?)为解决防止位拷贝,可通过定义自己的函数来实现。这个函数是什么样的呢?
1)由于是创建一个新的对象,所以应该是一个构造函数;
2)由于是用它来实现从已有对象创建新对象,那怎样把已有对象联系起来呢?可以把已有对象作为源对象作为这个函数的单一参数传递。由于这个源对象不能通过值传递的方式传入构造函数(因为定义这个函数就是为了处理按值传递方式),按句法传递一个指针是没有意义的,所以就用源对象的引用来传递。
这个函数就是拷贝构造函数。它经常被称为X(X&)(它叫做类X的外在表现)。
 
这样,有了拷贝构造函数,在用现有的对象创建新对象时,编译器将不再使用位拷贝,而是调用我们的拷贝构造函数。对于使用组合(或继承)的类,如果我们没有定义自己的拷贝构造函数,那么编译器会通过递归调用它所有成员对象(或基类)的拷贝构造函数来自动创建一个拷贝构造函数。编译器获得拷贝构造函数的过程被称为成员方法初始化。如下例,可尝试把Another类中的拷贝构造函数屏蔽看其运行结果:
#include<iostream>
using namespace std;
 
class exeEleven
{
      int i;
public:
     exeEleven( int ii = 0):i(ii)
     {
cout<<"enter exeEleven()....."<<endl;
     }
     exeEleven(const exeEleven& h)
     {
            cout<<"enter exeEleven(exeEleven&)...."<<endl;
     }
};
 
class WoCC
{
     int a;
public:
     WoCC(const int b=0):a(b)
     {
            cout<<"WoCC's constructor"<<endl;
     }
     WoCC(const WoCC& m)
     {
            cout<<"in WoCC's copy-constructor"<<endl;
     }
};
class Another       //combination
{
     int i;
     exeEleven ee;
     WoCC wo;
public:
     Another( int ii = 0):i(ii),ee(20)
     {
            cout<<"enter Another()..."<<endl;
     }
    
     Another(const Another& h) //----------- try to closs this function
     {
            cout<<"enter Another(Another&)..."<<endl;
     }
};
 
void main()
{
     cout<<"create a1----->"<<endl;
     Another a1(4);
     cout<<"create a2----->"<<endl;
     Another a2 = a1;
}
 
另外,通常在一个类中:如果我们没定义它的构造函数时,编译器会自动为它创建一个什么也不做的默认的构造函数;如果我们没有创建它的拷贝构造函数,编译器会自动创建一个仅执行位拷贝的拷贝构造函数;如果我们创建了它的拷贝构造函数,而没创建它的构造函数,那么编译器将不再自动为它创建构造函数,而是报错。
什么时候需要拷贝构造函数,而什么时候不需要拷贝构造函数呢?只有当准备用按值传递的方式传递类对象时,才需要拷贝构造函数;否则,则不需要。
       为了避免当没为类创建拷贝构造函数时,编译器会自动创建一个位拷贝的拷贝构造函数(组合和继承类除外),我们可以在类内声明一个私有的拷贝构造函数,不必定义,(除非成员函数或友元函数需要执行按值方式的传递),这样编译器就不会再自动创建了。