1、基类的构造函数不能为虚函数,因为对象不完整
2、不要在构造函数和析构函数里面调用虚函数,可能会发生未定义的行为
构造派生类对象时,首先调用基类构造函数初始化对象的基类部分。在执行基类构造函数时,对象的派生类部分是未初始化的。实际上,此时的对象还不是一个派生类对象。
析构派生类对象时,首先撤销/析构他的派生类部分,然后按照与构造顺序的逆序撤销他的基类部分。
因此,在运行构造函数或者析构函数时,对象都是不完整的。为了适应这种不完整,编译器将对象的类型视为在调用构造/析构函数时发生了变换,即:视对象的类型为当前构造函数/析构函数所在的类的类类型。由此造成的结果是:在基类构造函数或者析构函数中,会将派生类对象当做基类类型对象对待。
而这样一个结果,会对构造函数、析构函数调用期间调用的虚函数类型的动态绑定对象产生影响,最终的结果是:如果在构造函数或者析构函数中调用虚函数,运行的都将是为构造函数或者析构函数自身类类型定义的虚函数版本。 无论有构造函数、析构函数直接还是间接调用虚函数。
3、最好把基类的析构函数声明为虚函数
那么在什么情况下,析构函数要定义为虚函数呢?
看一个例子:
class Person
{
public:
virtual Person* BuyTickets()
{
cout << "买票" << endl;
return this;
}
~Person()
{
cout << "~Person" << endl;
}
};
class Student :public Person
{
public:
virtual Student* BuyTickets()
{
cout << "买票——半价" << endl;
return this;
}
~Student()
{
cout << "~Student" << endl;
}
protected:
int _num;
};
void Fun(Person& p)
{
p.BuyTickets();
}
void test()
{
Person* ptr = new Student;
delete ptr;
}
int main()
{
test();
system("pause");
return 0;
}
运行结果为:
可知只调用了基类的析构函数,改为虚函数为:
class Person
{
public:
virtual Person* BuyTickets()
{
cout << "买票" << endl;
return this;
}
virtual ~Person()
{
cout << "~Person" << endl;
}
};
class Student :public Person
{
public:
virtual Student* BuyTickets()
{
cout << "买票——半价" << endl;
return this;
}
~Student()
{
cout << "~Student" << endl;
}
protected:
int _num;
};
void Fun(Person& p)
{
p.BuyTickets();
}
void test()
{
Person* ptr = new Student;
delete ptr;
}
int main()
{
test();
system("pause");
return 0;
}