class Parent{
public:
virtual void func() { cout << "Parent" << endl; }
};
class Child : public Parent{
public:
void func() { cout << "Child" << endl; }
};
int main()
{
Child child;
Parent *p4 = &child;
p4->func(); //打印Child,父类指针p4竟然运行子类函数
return 0;
}
关于C++多态,我刚开始学的时候有一个疑惑:在Parent *p4 = &child;
的情况下:
p4明明是父类指针,怎么会调用到子类的成员函数呢?
请明确以下内容:
- p4是指向父类的指针,没有实体,调用成员时,一切都会按照父类的偏移量使用。
- 子类内存有父类那部分内容。
- 编译器将重写的虚函数安排到一个特殊的地址(这个地址就是虚函数表,虚表指针就是指向这个地址)。
- 编译器看到虚函数会覆盖虚函数表对应项。
根据以上基础内容,虚函数调用过程是:
1.按照父类偏移量偏移到虚表指针。
2.按照父类偏移量从虚表偏移到虚函数,这个虚函数就是被覆盖的虚函数。
那么为什么非虚函数不会调用到子类函数呢?
非虚成员是正常分配,是根据类自身偏移的。p4调用非虚成员,实际上就是调用从父类继承过来的那部分内存,所以调用的都是父类成员。
程序是编译后确定好的,子类(右值)各不相同(但是左右值地址相同、虚函数偏移量相同),看着像虚函数根据右值动态在变,所以被称为动态多态。
不要试图用指针一个个看对象的内存布局,C++标准没有规定布局,不同编译器对象内存布局不一定相同。
注意:如果子类的继承方式是private,由于父类的虚函数对子类不可见,子类不能override父类的虚函数,那么多态是无效的。