多态的概念
多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数
多态的两个条件
1.虚函数重写
2.父类的指针或者引用调用虚函数
重写的注意事项
只有成员函数才能加virtual,全局函数不可以,成员静态函数也不可以
虚函数重写(覆盖)的条件
虚函数+三同(函数名,返回值,参数)
不符合重写,就构成隐藏关系(函数名相同)
但是又有两个特例
1.子类函数前面不加virtual,但是依旧可以构成重写
2.“重写的协变”,返回值可以不同,但是要求必须是父子关系的指针或者引用
class A {
public:
virtual void func() {
cout << "A::func()" << endl;
}
int _a;
};
class B : public A{
public:
virtual void func() {
cout << "B::func" << endl;
}
int _b;
};
int main() {
A* a = new B;
a->func();
return 0;
}
这是执行结果
重写成功,并且父类的指针调用子类的虚函数
为什么可以完成这样的操作呢?
虚表
vfptr:虚函数表指针
虚表是指向一个函数指针数组的指针,
这个数组称为:vtbl,存放着虚函数地址的数组
子类和父类都有各自的虚表,放着自己的虚函数地址,运行时多态就是通过这个来实现的,虚表
在构造期间不要调用virtual函数,不会是你期待的效果
多态的其他问题
静态成员函数可以是虚函数吗?为什么?
不可以,静态成员函数没有this指针,没有办法直接通过对象来调用,一般都是类名::函数()这样调用
inline函数可以是虚函数吗?为什么?
可以,是不是很奇怪?inline函数没有地址,实现虚函数要放在虚表里面,这都没有地址怎么放?
inline是对编译器的“建议”,我们用virtual修饰了,编译器当然可以拒绝inline,所以它本质不是inline函数
构造函数可以是虚函数吗?为什么?
不可以,在函数构造的时候虚表指针还没有初始化,注意是虚表指针,不是虚表,虚表指针在构造函数的初始化列表进行初始化,所以不能是虚函数,虚函数表一般放在常量区
析构函数可以是虚函数吗?为什么?
可以,并且非常建议把析构函数设置成虚函数,这样可以有效的放在内存方面的问题