在网络上经常会有出现”X(X&)”这个术语.这个就是指拷贝构造函数.很多人还是不知道.也难怪在QQ群中要是有人问起这是什么意思?知道的人通常会以一个来回答.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

X(X&)的意思是:X引用的X.

要是再来一个:X(const X&);? 嘿嘿

 

理解拷贝构造函数需要知道C++的引用基本概念和函数的按值传递方式.否则的话你不但很难理解.而且还会很容易混淆.

 

这笔记说是复习拷贝构造函数.本质上还是说: 引用基本概念和函数的按值传递方式

 

引用基本概念:

引用(&)说是指针.但又不是指针.但它像一个自动让编译器进行逆向使用的指针.最经常使用的地方就是:函数的形参和返回值.当然了.也是可以独立使用的.所以说像指针但又不是.

使用引用的一些规则以及与指针的不同点:

1.     引用被声明的时候.必须要进行初始化.//这点就与指针不同了.指针可以在任何时候初始化.好的程序风格在声明指针的时候也进行初始化.以免忘记.

2.     一个引用被指向一个对象的时候,就不能再指向其它的对象.//指针则可以.

3.     必须要与一块合法的存储单元关连.也就是说不能有NULL的引用.//指针则可以声明为NULL

 

函数的按值传递概念

这个..按值最最基础的概念就是不会改变原来的值.仅知道这个对于理解拷贝构造还是不够的.还要知道编译器如何传递和返回的.

举例说明:

int Example_A_Function(int Para_A,int Para_B)

{

int Sum;

     Sum=Para_A+Para_B;

     return Sum;

}//注意:CC++,函数的参数入栈是从右到左.也就是说Para_B先进,再是Para_A,最后返回地址入栈.

 

对上面的函数进行汇编:

_Example_A_Function proc near

push bp
mov bp,sp;
建立堆栈框架
sub sp,2
 
mov ax,word ptr [bp+4];
取参数Para_A

add ax,word ptr [bp+6];加参数Para_B
mov word ptr [bp-2],ax
mov ax,word ptr [bp-2]
mov sp,bp;
释放堆栈框架
pop bp
ret
_Example_A_Function endp

而栈顶的则如下图所示:

 

传递的方式就是这样子咯.那么如何返回呢?编译器把得到的结果放在寄存器中.结束的时候就把寄存器中的值取出来给调用者.

以上这些是编译器的内置的类型.如果是你自己定义的呢?比如一个类,一个结构.是怎么实现的呢?

拿结构来打比方://嘿嘿.看到了吧.又是结构.^_^

Example_B

{

     int stru_Buffer[100];

     double stru_A;

     long stru_B;

     char stru_C;

}Test_A,Test_B;

Example_B Example_B_Function(Example Test_C)

{

     …//做一些其它事

     return Test_C;

}

main()

{

     Test_B=Example_B_Function(Test_A);

}

main()函数中,首先调用函数Example_B_Function(),整个Test_A的内容被压栈.但是这时候就会发现此时有附加的动作了:在调用之前Test_B就被压入栈了.问题就在这儿了.Test_B不是一个参数.怎么办?不管它.软考没有要求这个.所以我就不多说.有兴趣的朋友(也不能说是有兴趣,做一名合格的工程师,这也是必须了解的内容.)可以去看看:约束,栈的框架,重入,bit拷贝等等,就知道是如何处理Test_B.

 

有了以上的两上基础概念,理解拷贝构造函数好办好多.

 

拷贝构造函数概念

构造函数是创建一个新的对象,而传递给这个函数的参数必须是我们创立的对象的源对象.但是这个对象是不能被传入的构造函数的.

咋办?用指针吗?明显不行的,因为按照规则构造一个指针来传递是没有任何意义的.根本的原因是我们现在是从对象创建新对象.而此时引用就可以派上用场了.它可以对源对象的引用.

处理这个过程的函数就是拷贝构造函数了.

什么时候调用呢?

当用一个已经被初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用.

以下三点都可以自动调用拷贝构造函数:

1.     一个对象以值传递的方式传入函数体

2.     一个对象以值传递的方式从函数返回

3.     一个对象需要通过另外一个对象进行初始化

 

缺省的拷贝构造函数

1.      如果在类中没有显式地声明一个拷贝构造函数,编译器将会自动生成一个默认的拷贝构造函数,该构造函数完成对象之间的bitcopy(位拷贝).//这里还有二个术语:浅拷贝和深拷贝.百度搜一下就有了.

2.      当定义更复杂的类型时,如果没有创建显示的拷贝构造函数,C++也将自动地为我们创建拷贝构造函数.但是在这时用位拷贝是没有意义的,它并不能达到我们的目的.

3.     创建类的时候可以使用组合的方法来进行创建.当我们要用到这个类来处理一些事情的时候,你如果加了一个拷贝构造函数.就等于告诉了编译器我们要自己处理构造函数的创建,而编译器就不会提供缺省的构造函数,并且除非我们有创建一个显示的拷贝构造函数.否则将会编译出错.

[这些例子在网络上都有很多,限于篇幅,就不举了]

 

是否选择显示定义拷贝构造函数?

说实在的话,即时你不定义你也可以写出功能类来.但是.仅仅准备用传值的方式传递类的对象时候,此时才用到,如果不要这么做,那么就不用了.

当你选择了要用到拷贝构造函数时候有二个地方要看:

1.      防止按值传递

有两种方法:

className(const className&);或把拷贝构造函数声明为private

2.      改变外部对象的函数

这种做法读起代码有点郁闷,但是我们如果要修改一个非const或被声明为private的外部对象的时候,就比较好了,也比较好理解代码.

< Inside the C++ Object Model >一书也有关于拷贝构造函数的一些使用信息:

[Copy Constructor Construction]

There are three program instances in which a class object is initialized with another object of its class. The most obvious instance, of course, is an object's explicit initialization, such as

   class X { ... };

   X x;

   // explicit initialization of one class object with

another

   X xx = x;

The other two are when an object is passed as an argument to a function, such as

extern void foo( X x );

void bar()

{

   X xx;

   // implicit initialization of foo()'s

   // first argument with xx

   foo( xx );

}

and when a function returns a class object, such as

X

foo_bar()

{

   X xx;

   // ...;

   return xx;

 }

Say the class designer explicitly defines a copy constructor (a constructor requiring a single argument of its class type), such as either of the following:

// examples of user defined copy constructors

// may be multi-argument provided each second

// and subsequent argument is provided with a

// default value

X::X( const X& x );

Y::Y( const Y& y, int = 0 );

In this case, that constructor is invoked, under most circumstances, in each program instance where initialization of one class object with another occurs. This may result in the generation of a temporary class object or the actual transformation of program code (or both).