- 虚函数
通过基类的指针调用该成员函数时,将根据指针指向的对象类型确定调用的函数,而非指针的类型
是C++ 多态的一种体现,属于 函数的重写, 而非 重载。 要求函数的名称,参数完全一致。
class Animal
{
public:
void eat() {
std::cout << "I'm eating animal food."
}
};
class Dog : public Animal
{
public:
void eat() {
std::cout << "I'm eating a bone."
}
};
Animal *animal = new Animal;
Dog *dog = new Dog;
Animal *animal2 = new Dog;
animal ->eat();
cat ->eat();
animal2 ->eat();
输出:
I’m eating animal food.
I’m eating a bone.
I’m eating animal food.
但是,如果把基类中函数设置成 virtual 虚函数,则结果就不同:
class Animal
{
public:
virtual void eat() {
std::cout << "I'm eating animal food."
}
};
class Dog : public Animal
{
public:
void eat() {
std::cout << "I'm eating a bone."
}
};
Animal *animal = new Animal;
Dog *dog = new Dog;
Animal *animal2 = new Dog;
animal ->eat();
cat ->eat();
animal2 ->eat();
输出:
I’m eating animal food.
I’m eating a bone.
I’m eating animal bone.
- 虚继承
class Biology
{
public:
Biology() {
std::cout << "Biology Constructor."
}
~Biology() {
std::cout << "Biology Destructor."
}
};
class Animal: public Biology
{
public:
Animal() {
std::cout << "Animal Constructor."
}
~Animal() {
std::cout << "Animal Destructor."
}
};
class Plant: public Biology
{
public:
Plant() {
std::cout << "Plant Constructor."
}
~Plant() {
std::cout << "Plant Destructor."
}
};
class SeaAnemone: public Animal, public Plant
{
public:
SeaAnemone() {
std::cout << "SeaAnemone Constructor."
}
~SeaAnemone() {
std::cout << "SeaAnemone Destructor."
}
};
int main(int argc,char* argv[])
{
SeaAnemone *SeaAnemone;
return 0;
}
输出的结果为:
Biology Constructor.
Animal Constructor.
Biology Constructor.
Plant Constructor.
SeaAnemone Constructor.
SeaAnemone Destructor.
Plant Destructor.
Biology Destructor.
Animal Destructor.
Biology Constructor.
这样是有问题的, 基类的构造和析构都被调用了两次。
如果改成虚继承,则不会出现该问题:
class Biology
{
public:
Biology() {
std::cout << "Biology Constructor." << endl;
}
~Biology() {
std::cout << "Biology Destructor." << endl;
}
};
class Animal: virtual public Biology
{
public:
Animal() {
std::cout << "Animal Constructor." << endl;
}
~Animal() {
std::cout << "Animal Destructor." << endl;
}
};
class Plant: virtual public Biology
{
public:
Plant() {
std::cout << "Plant Constructor." << endl;
}
~Plant() {
std::cout << "Plant Destructor." << endl;
}
};
class SeaAnemone: public Animal, public Plant
{
public:
SeaAnemone() {
std::cout << "SeaAnemone Constructor." << endl;
}
~SeaAnemone() {
std::cout << "SeaAnemone Destructor." << endl;
}
};
输出的结果为:
Biology Constructor.
Animal Constructor.
Plant Constructor.
SeaAnemone Constructor.
SeaAnemone Destructor.
Plant Destructor.
Animal Destructor.
Biology Constructor.
虚基类可以使得从多个类(它们继承自一个类)中派生出的对象只继承一个对象.
而且当 析构函数被调用多次时, 程序会报错的。
- 虚析构
#include<iostream>
using namespace std;
class Biology
{
public:
Biology() {
name = new char[16];
std::cout << "Biology Constructor." << endl;
}
virtual ~Biology() {
delete []name;
std::cout << "Biology Destructor." << endl;
}
private:
char *name;
};
class Animal: virtual public Biology
{
public:
Animal() {
std::cout << "Animal Constructor." << endl;
}
~Animal() {
std::cout << "Animal Destructor." << endl;
}
};
class Plant: virtual public Biology
{
public:
Plant() {
std::cout << "Plant Constructor." << endl;
}
~Plant() {
std::cout << "Plant Destructor." << endl;
}
};
class SeaAnemone: public Animal, public Plant
{
public:
SeaAnemone() {
std::cout << "SeaAnemone Constructor." << endl;
}
~SeaAnemone() {
std::cout << "SeaAnemone Destructor." << endl;
}
};
int main(int argc,char* argv[])
{
Biology *seaAnemone = new SeaAnemone();
delete seaAnemone;
return 0;
}
如果公共基类Biology的析构函数,不声明为virtual, 则 执行会报错。
声明为virtual 则不会报错了。
所以我们一定要注意在基类的析构函数前面加上virtual,使其变成虚析构在C++程序中使用虚函数,
虚继承和虚析构是很好的习惯 可以避免许多的问题。
- 纯虚函数
在C++中的一种函数申明被称之为:纯虚函数(pure virtual function).它的申明格式如下:
class CShape
{
public:
virtual void Show()=0;
};
注意红色部分,在普通的虚函数后面加上"=0"这样就声明了一个pure virtual function.
在什么情况下使用纯虚函数(pure vitrual function)?
1,当想在基类中抽象出一个方法,且该基类只做能被继承,而不能被实例化;
2,这个方法必须在派生类(derived class)中被实现;
- 虚构造函数
构造函数不能是虚的
- Private 虚函数
class A
{
public:
void foo() { bar();}
private:
virtual void bar() { ...}
};
class B: public A
{
private:
virtual void bar() { ...}
};
在这个例子中,虽然bar()在A类中是private的,但是仍然可以出现在派生类中,
并仍然可以与public或者protected的虚函数一样产生多态的效果。
并不会因为它是private的,就发生A::foo()不能访问B::bar()的情况,
也不会发生B::bar()对A::bar()的override不起作用的情况。
这种写法的语意是:A告诉B,你最好override我的bar()函数,但是你不要管它如何使用,也不要自己调用这个函数。
- 构造函数和析构函数中的虚函数调用
一个类的虚函数在它自己的构造函数和析构函数中被调用的时候,它们就变成普通函数了,不“虚”了。也就是说不能在构造函数和析构函数中让自己“多态”。
class A
{
public:
A() { foo();} // 在这里,无论如何都是A::foo()被调用!
~A() { foo();} // 同上
virtual void foo();
};
class B: public A
{
public:
virtual void foo();
};
void bar()
{
A * a = new B;
delete a;
}
如果你希望delete a的时候,会导致B::foo()被调用,那么你就错了。
同样,在new B的时候,A的构造函数被调用,但是在A的构造函数中,被调用的是A::foo()而不是B::foo()。
https://www.jianshu.com/p/b470594c81ec
https://www.cnblogs.com/hairuijy/p/10483010.html
https://blog.csdn.net/ithomer/article/details/6031329
https://baijiahao.baidu.com/s?id=1653132502323288772&wfr=spider&for=pc
https://blog.csdn.net/jirryzhang/article/details/79392934
https://blog.csdn.net/false_mask/article/details/81662117