有些看着是理所当然的东西有时候往往被我们忽略其深层次的意义,比如复制构造函数的形参被设计为引用类型,这是为什么捏?
类名 (类名 &ref)
{
......
}
可是当时就没有想想它的形参为什么设计成引用类型,而不是对象或者指针类型呢?
首先,我想编译器这么规定是有他的道理的!! 以下愚见只供参考。
1) 引用比较高效 :
如果形参是对象类型的,那么它是否也要实例化? 而且 整个对象进行拷贝, 效率不高,很不划算。
如果形参是指针类型的, 从编译的角度来 看 :
程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。指针相当于中介,租房的时候直接跟房东谈比较划算 还是通过中介介绍划算,我想这个不用我说了吧(虽然我还没租过房)。
2) 形参为对象类型是行不通的 :
复制构造函数也是构造函数,只不过它比较特别而已。上一条也提到了,如果形参是对象,在被调用时形参也需要实例化(构造)。那么它的构造是不是也有点类似于, 形参 = 实参 ;这么说来,这不是在调用复制构造函数麽? 之后调用复制构造函数的形参又要 实例化,又调用复制构造函数,没完没了。在复制构造函数的形参中调用了自 个儿,这不就是递归调用麽? 这还不怎么要紧,如果 是我们平常使用递归往往会有出口点,但这里的是个死递归,这才要了命!(其实也要不了命,呵呵)
综上所述,以引用作为形参最为合适而且高效
众所周知,c++中类没有给出复制构造函数的话,编译器会自动补上一个,然而对于深拷贝来说编译器给的复制构造函数是无法胜任的。这时候,我们就要自己动手实现这个复制构造函数。
class Animal
{
public:
Animal()
{
name = NULL;
age = 0;
}
Animal(const Animal &a)
{
cout << "copy constructor & runnig..." << endl;
int len = strlen(a.name);
name = new char[len + 1];
strcpy(name, a.name);
age = a.age;
//......
}
~Animal()
{
if (name != NULL) {
delete []name;
}
}
// protected:
char *name;
int age;
};
int main()
{
Animal a;
Animal b = a;
return 0;
}
我们往往被告知复制构造函数的格式是固定的,如下:
类名 (类名 &ref)
{
......
}
可是当时就没有想想它的形参为什么设计成引用类型,而不是对象或者指针类型呢?
首先,我想编译器这么规定是有他的道理的!! 以下愚见只供参考。
1) 引用比较高效 :
如果形参是对象类型的,那么它是否也要实例化? 而且 整个对象进行拷贝, 效率不高,很不划算。
如果形参是指针类型的, 从编译的角度来 看 :
程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。指针相当于中介,租房的时候直接跟房东谈比较划算 还是通过中介介绍划算,我想这个不用我说了吧(虽然我还没租过房)。
2) 形参为对象类型是行不通的 :
复制构造函数也是构造函数,只不过它比较特别而已。上一条也提到了,如果形参是对象,在被调用时形参也需要实例化(构造)。那么它的构造是不是也有点类似于, 形参 = 实参 ;这么说来,这不是在调用复制构造函数麽? 之后调用复制构造函数的形参又要 实例化,又调用复制构造函数,没完没了。在复制构造函数的形参中调用了自 个儿,这不就是递归调用麽? 这还不怎么要紧,如果 是我们平常使用递归往往会有出口点,但这里的是个死递归,这才要了命!(其实也要不了命,呵呵)
综上所述,以引用作为形参最为合适而且高效
文章来源:http://blog.chinaunix.net/uid-27034868-id-3850588.html