一、多态机理
#include <iostream>
class Father
{
public:
virtual void Func1()
{
std::cout << "Fahter::Func1()" << std::endl;
}
virtual void Func2()
{
std::cout << "Fahter::Func2()" << std::endl;
}
virtual void Func3()
{
std::cout << "Fahter::Func3()" << std::endl;
}
private:
size_t count_;
};
class Son : public Father
{
public:
virtual void Func2()
{
std::cout << "Son::Func2()" << std::endl;
}
};
using FUNC = void (*)();
int main()
{
Father *pfather = new Father;
Son *pson = new Son;
// 得到指向虚函数表指针的地址。
long *pvptr_father = (long *)pfather;
long *pvptr_son = (long *)pson;
// 得到指向虚函数表的指针。
long *vptr_father = (long *)(*pvptr_father);
long *vptr_son = (long *)(*pvptr_son);
FUNC func1_father, func2_father, func3_father;
func1_father = (FUNC) * (vptr_father + 0); // 得到虚函数 Father::Func1() 的地址。
func2_father = (FUNC) * (vptr_father + 1); // 得到虚函数 Father::Func2() 的地址。
func3_father = (FUNC) * (vptr_father + 2); // 得到虚函数 Father::Func2() 的地址。
func1_father();
func2_father();
func3_father();
std::cout << std::endl;
FUNC func1_son, func2_son, func3_son;
func1_son = (FUNC) * (vptr_son + 0); // 得到虚函数 Father::Func1() 的地址。
func2_son = (FUNC) * (vptr_son + 1); // 得到虚函数 Son::Func2() 的地址。
func3_son = (FUNC) * (vptr_son + 2); // 得到虚函数 Father::Func2() 的地址。
func1_son();
func2_son();
func3_son();
return 0;
}
结果:
Fahter::Func1()
Fahter::Func2()
Fahter::Func3()
Fahter::Func1()
Son::Func2()
Fahter::Func3()
二、分析

上图介绍了C++多态的实现机理。注意:虚函数表属于类,虚函数表指针属于对象。
子类继承父类时,会得到和父类相同的虚函数表,该表记载着代码区中属于该类的虚函数的起始地址。当子类没有重写虚函数时,程序调用子类的虚函数,就相当于调用父类的虚函数。当子类重写了父类的虚函数时,相当于将子类的虚函数表中的相应虚函数的地址修改为子类虚函数的首地址,从而完成了多态!
三、对象切割
Son sn;
Father fa = sn;
fa.Func1();
fa.Func2();
fa.Func3();
结果:
Fahter::Func1()
Fahter::Func2()
Fahter::Func3()
对于多态,使用指针或者引用,用父类调用子类的函数达到工厂模式的目的。倘若用子类直接赋值给父类,会有什么结果呢。上述代码就展示了最后的结果,并没有调用子类的函数,而是直接调用了父类的函数。
原因是直接用子类给父类对象赋值,子类中的属于父类部分内容会被编译器自动切割出来并拷贝给了父类。
实际上上述操作一共干了两件事情,
1、生成 Father 对象。
2、用 sn 来初始化 Father 对象。显然,编译器并没有将 sn 的虚函数表指针覆盖掉 fa 的虚函数表指针。
四、总结
1、类只有包含了虚函数才存在虚函数表(只有一个),同属于一个类的对象共享虚函数表,但是有各自的vptr(虚函数表指针)。
2、父类含有虚函数,子类就会有一个虚函数表,但是子类的虚函数表只是和父类的虚函数表中的内容相同,所在的内存位置不同。
3、多态是子类赋值给父类的指针或者引用。若直接对象赋值,是对象切割的范畴。
(SAW:Game Over!)
本文深入探讨C++中多态的实现原理,通过代码示例解析虚函数表的工作机制,展示子类如何通过重写父类虚函数实现多态。同时,分析对象切割现象及其对多态的影响。
11万+

被折叠的 条评论
为什么被折叠?



