Author:阿冬哥
Created:2013-4-20
Blog:http://blog.csdn.net/c359719435/
Copyright 2013 阿冬哥 http://blog.csdn.net/c359719435/
使用以及转载请注明出处
1 构造函数和析构函数
构造函数和析构函数是C++中面向对象的基本概念,每本教科书中都会有详细的定义和介绍。简单的理解就是,构造函数是对象生成时调用的与类名同名的函数,用以分配类对象的内存以及初始化成员。析构函数则是类的对象在生命周期完成时调用的函数,用以释放对象占用的内存。
class MyClass{
public:
MyClass(){ cout << "class MyClass constructor" << endl;}
~MyClass(){ cout << "class MyClass destructor" << endl;}
int mAttr;
};
2 构造函数类型
2.1 默认构造函数(default constructor)
上述我们定义的类中没有定义显式的constructor,则编译器会自动为该类生成public constructor。注意编译器生成默认构造函数的前提是类中没有显式定义构造函数,如果我们自己定义了构造函数,无论public还是private,则编译器不会再生成默认构造函数。还要注意的是,编译器生成的默认构造函数只会对自定义对象类型的成员变量做初始化,不会对内置类型的成员变量做初始化。
以下的MyClass没有定义构造函数,则编译器会自动生成默认构造函数。
class MyClass{
public:
//MyClass(){ cout << "class MyClass constructor" << endl;}
~MyClass(){ cout << "class MyClass destructor" << endl;}
int mAttr;
};
如果有带参数的自定义构造函数,则需要注意正确定义类的对象。
class MyClass{
public:
MyClass(int i): mAttr(i){
cout << "class MyClass constructor" << endl;
}//this is the constructor defined by user
};~MyClass(){ cout << "class MyClass destructor" << endl;}
int mAttr;
void ClassTest1(){
MyClass test;//here should be error in complie, because do not have constructor MyClass()
MyClass *ptr = MyClass();//here should be error in complie, because do not have constructor MyClass()
MyClass test(2);// it is right
}
2.2 拷贝构造函数(copy constructor)
拷贝构造函数(也叫复制构造函数)是一种特殊的构造函数,具有单个形参,该形参是对该类类型的引用。有default copy constructor和defined copy constructor之分。
首先,来看看C++的两种初始化形式:直接初始化(direct-initialization)、复制初始化(copy-initialization)。
直接初始化:初始化式放在圆括号中。例如:MyClass test(2);
复制初始化:使用=。例如:MyClass test1 = test; or MyClass test2 = MyClass(2);
直接初始化很简单,调用一次构造函数。复制初始化会调用拷贝构造函数(而不是其他构造函数)。看下面的例子:
参考http://blog.csdn.net/lwbeyond/article/details/6202256
class MyClass{
public:
MyClass(){ cout << "class MyClass constructor" << endl;}
~MyClass(){ cout << "class MyClass destructor" << endl;}
int mAttr;
2.3 什么时候运行拷贝构造函数};
void ClassTest2(){
MyClass test1;
MyClass test2 = test1;// #####这里的赋值实际上是调用了ClassTest2默认拷贝函数
}
void ClassTest3(){
MyClass test2 = MyClass(2);// #####这里先调用MyClass的构造函数创建一个临时变量,
//然后调用MyClass的默认拷贝构造函数初始化test2.
}
运行ClassTest2:
class MyClass constructor
class MyClass destructor
class MyClass destructor
从这个运行结果看只有执行一次constructor,但是有两次destructor。原因是调用了copy-constructor。
运行ClassTest3:
class MyClass constructor
class MyClass destructor
从这个运行结果看,只执行一次constructor和destructor,貌似没有临时变量。这个跟编译器的优化有关。
在MyClass中增加一个拷贝构造函数:class MyClass{
public:
MyClass(){ cout << "class MyClass constructor" << endl;}
~MyClass(){ cout << "class MyClass destructor" << endl;}
MyClass MyClass(const MyClass &tmp){
this.mAttr = tmp.mAttr;
return this;
}
int mAttr;
};
运行ClassTest2:
class MyClass constructor
class MyClass copy-destructor
class MyClass destructor
class MyClass destructor
从这个运行结果看只有执行一次constructor,copy-constructor,但是有两次destructor。
运行ClassTest3:
class MyClass constructor
class MyClass destructor
从这个运行结果看,只执行一次constructor和destructor,没有调用copy-constructor。这个是编译器的优化的结果,具体解释请看http://blog.csdn.net/snicolashe/article/details/6925972
以下三种情况会调用拷贝构造函数:
1) 一个对象作为函数参数,以值传递的方式传入函数体;2) 一个对象作为函数返回值,以值传递的方式从函数返回;3) 一个对象用于给另外一个对象进行初始化(常称为复制初始化)
3 虚析构函数
首先来看一个例子:
class MyBase
{
public:
long mAttr;
MyBase():mAttr(1){cout << " MyBase constructor" << endl;
~MyBase(){cout << "MyBase destructor" << endl;}
};
class Child: public MyBase
{
public:
Child(){cout << "Child constructor" << endl;}
~Child(){cout << "Child destructor" << endl;}
};
void ClassTest2(){
MyBase *b;
Child *c;
c = new Child;
b=c;
delete b;
}
运行ClassTest2:
MyBase constructor
Child constructor
MyBase destructor
为什么会是这样的结果,相信大部分人都知道,因为父类的析构函数不是虚析构函数。
将上述代码MyBase的析构函数改成虚析构函数,则运行结果:
MyBase constructor
Child constructor
Child destructor
MyBase destructor
这里的解释是:Child的虚函数表中,Chlid的析构函数覆盖了MyBase的析构函数。
可是,Child和MyBase的析构函数名不同,怎么覆盖呢?事实上,所有类的析构函数在编译时名字都是Destructor,所以析构看上去名字不一样,但对编译器就是一样的名字,也能运用虚函数的处理规则了。
再就是,Chlid的析构函数覆盖了MyBase的析构函数,那么怎么会调用MyBase的析构函数呢?实际上编译器对虚的析构函数做了特殊处理,在子类的虚析构函数执行完后,自动调用父类的析构函数,代码都是编译器处理的,它当然知道一个类的父类是谁,父类的析构函数是哪个。
4 构造函数禁止拷贝
禁止拷贝只需要把拷贝构造函数声明为private即可。