类的构造函数、析构函数与赋值函数
1、一个空类,编译器会默认为其生产六个函数,常用的有四种
class A
{
A(void); // 缺省的无参数构造函数
A(const A &a); // 缺省的拷贝构造函数
~A(void); // 缺省的析构函数
A & operate =(const A &a); // 缺省的赋值函数
}
很多人认为编写一个空类,编译器就会做这些事,错了,这些缺省函数只在需要的时候编译器才会生成,也就是如果不需要,那么就不会生成。
2、构造函数
(1)构造函数尽量用初始化列表进行初始化,效率高
class A
{
public:
A();
A(string s, int i):name(s), id(i){} ; // 初始化列表
private:
string name;
int id;
};
(2)const只能在初始化列表中进行初始化,此外每个类对象的const变量的值并不一样,若要定义一个类常量,用enum。
(3)若类存在继承关系,派生类必须在初始化列表中调用基类的构造函数,跟java一样,只是java已经默认在首行调用个。1. class B : public A
{
B(string s, int i);// B的构造函数
};
B::B(string s, int i) : A(s, i) // 在初始化表里调用A的构造函数
{
}
3、析构函数
将2中得初始化列表修改为
A(string s, int i):id(i), name(s){} ; // 初始化列表
初始化顺序该是如何呢?不管怎么样,成员初始化都是遵循声明顺序的,为什么呢?
因为构造函数可以有多个,而析构函数就一个,如果没有一个统一的顺序,那么析构函数就无法得到一个统一的逆序。
4、可否在构造函数中和析构函数中调用虚函数呢?
含有纯虚函数的基类不能构造出对象,所以在基类中得构造函数和析构函数中不能调用纯虚函数。
对于非纯虚函数,可以调用,但是派生类Derived构造对象时需先调用基类的构造函数,此时基类构造函数中调用的虚函数仍属于基类,因为派生类对象还未构造完成;反之析构函数也是,析构完派送类对象时,最后析构基类部分时的非纯虚函数仍调用的基类。
举例:
class ClassA
{
public:
ClassA()
{
cout<<"ClassA::ClassA() begin"<<endl;
Print();
cout<<"ClassA::ClassA() end"<<endl;;
}
virtual void Print()
{
cout<<"ClassA::Print()"<<endl;
}
virtual ~ClassA()
{
cout<<"ClassA::~ClassA() begin"<<endl;
Print();
cout<<"ClassA::~ClassA() end"<<endl;;
}
};
class ClassB : public ClassA
{
public:
ClassB()
{
cout<<"ClassB::ClassB() begin"<<endl;
Print();
cout<<"ClassB::ClassB() end"<<endl;;
}
void Print()
{
cout<<"ClassB::Print()"<<endl;
}
~ClassB()
{
cout<<"ClassB::~ClassB() begin"<<endl;
Print();
cout<<"ClassB::~ClassB() end"<<endl;;
}
};
int main(void)
{
ClassB* pB = new ClassB;
cout<<endl;
ClassA* pA = pB;
pA->Print();
cout<<endl;
delete pB;
return 0;
}
ClassA::ClassA() begin
ClassA::Print() //派生类还未构造完成,调用的虚函数属于基类
ClassA::ClassA() end
ClassB::ClassB() begin
ClassB::Print()
ClassB::ClassB() end
ClassB::Print() //派生类构造完成,调用的虚函数属于派生类
ClassB::~ClassB() begin
ClassB::Print()
ClassB::~ClassB() end
ClassA::~ClassA() begin
ClassA::Print() //派生类部分析构完成,调用的虚函数属于基类
ClassA::~ClassA() end
5、赋值函数
这部分我把缺省的拷贝构造函数和缺省的赋值函数放在一块比较
A(const A &a); // 缺省的拷贝构造函数
A & operate =(const A &a); // 缺省的赋值函数
二者最大的区别:缺省的拷贝构造函数属于构造函数,对象还未创建,没有返回值;缺省的赋值函数属于普通函数,对象已经创建,有返回值。
此外拷贝构造函数不需要检验源对象是否和新建对象相同,而赋值函数需要检验源对象是否和被赋值对象相同,因为如果被赋值的对象分配了内存,需要先释放原来的内存资源然后根据源对象重新分配内存,如果两者相同,等于把自身的内存释放了,就会出现错误。