构造函数
构造函数与类同名,没有返回类型,可重载
需要注意的是,在初始化对象时,调用的是其构造函数或拷贝构造函数,而不会调用赋值函数,这是因为赋值运算符是在一个现存的对象被赋予新的值的时候才被调用,而拷贝构造函数在调用期间,这个对象还处于未决状态
构造函数不能是虚函数,若是给构造函数加上virtual ,编译是不能通过的。这是为什么呢?这是因为在调用构造函数的时候,虚函数表里面还是空的,如果声明构造函数为虚函数,则动态联编无法实现。同理,拷贝构造函数也不能虚函数,赋值构造函数也不能是虚函数。
自定义构造函数可以给每个类成员初始化,冒号与花括号之间的是初始化列表。有一点要注意的是,初始化成员的顺序不是按照初始化列表的顺序,而是按照在类中声明的顺序。
析构函数
析构函数可以是虚函数,若声明基类的析构函数为虚函数,存在一个基类指针指向派生类对象的时候,会调用派生类和基类的析构函数。然而,若基类的析构函数不是虚函数时,只会调用基类的析构函数,这就会导致派生类部分释放不彻底了。看下面的例子,在这个例子中基类的析构函数没有声明是虚函数,于是程序执行之后只调用了基类的析构函数。
class Base{
public:
Base(){
printf("Base is constructed\n");
}
Base(const Base &other){
printf("Base copy\n");
}
~Base(){//基类的析构函数不是虚函数
printf("Base is disconstructed\n");
}
Base &operator=(const Base &other){
printf("Base is =\n");
}
};
class Derived:public Base//默认继承是私有
{
public:
Derived(){
printf("Derived is constructed\n");
}
~Derived(){
printf("Derived is disconstructed\n");
}
Derived &operator=(const Derived &other){
printf("Derived is =\n");
}
Derived(const Derived &other){
printf("Derived copy\n");
}
};
int main(){
Base *bp=new Derived();
delete bp;//用delete的时候要注意,如果之前没有用到new,会报错,因为不知道要释放哪里的内存
return 0;
}
还有一个很有意思的地方,用new构造一个派生类对象给基类对象时,析构函数和构造函数的调用次序是很有意思的:
class Base{
public:
Base(){
printf("Base is constructed\n");
}
Base(const Base &other){
printf("Base copy\n");
}
virtual ~Base(){
printf("Base is disconstructed\n");
}
Base &operator=(const Base &other){
printf("Base is copied\n");
}
};
class Derived:public Base//默认继承是私有
{
public:
Derived(){
printf("Derived is constructed\n");
}
~Derived(){
printf("Derived is disconstructed\n");
}
Derived &operator=(const Derived &other){
printf("Derived is copied\n");
}
Derived(const Derived &other){
printf("Derived copy\n");
}
};
int main(){
//Derived();
Base b=Derived();//首先会构造一个派生类,于是调用基类构造函数以及派生类构造函数,然后把这个派生类对象拷贝给基类对象,于是调用基类拷贝构造函数,
//随后释放派生类对象,最后释放基类对象
//b=&c;
//delete bp;
return 0;
}
运行结果如下: