前面介绍了虚函数是以间接引用的方式实现“不同国家的人说不同语言”的功能,本篇对其过程进行了模拟实现。
1.步骤总结:
//(1)找到对象头部四个字节--虚表 //(2)根据虚函数的位置(在cpp中定义的顺序),确定该虚函数在虚表的下标 //(3)找到对应的虚函数地址,直接调用该地址
用下图也可以看出
2.学习视频地址:虚函数的模拟实现
3.学习笔记
(1)整体结构如下图:
(2)Chinese.h/cpp
Chinese
#pragma once #include#include "Person.h" class CChinese :public CPerson { public: CChinese() { m_pVirTable = m_ChsTable; } ~CChinese() { } void speak() { printf("Speak Chinese!"); } //每一个类有自己的虚表 static PEN_VIRTUAL m_ChsTable[2]; };
Chinese.cpp
#include "Chinese.h"
//函数覆盖
PEN_VIRTUAL CChinese::m_ChsTable[2] = { (PEN_VIRTUAL)&CChinese::speak, (PEN_VIRTUAL)&CPerson::eat };
(3)English.h/cpp
English.h
#pragma once #include#include "Person.h" class CEnglish :public CPerson { public: CEnglish() { m_pVirTable = m_EngTable; } ~CEnglish() { } void speak() { printf("Speak English"); } void eat() { printf("Eat English"); } //每一个类有自己的虚表 static PEN_VIRTUAL m_EngTable[2]; };
English.cpp
#include "English.h"
//函数覆盖
PEN_VIRTUAL CEnglish::m_EngTable[2] = { (PEN_VIRTUAL)&CEnglish::speak, (PEN_VIRTUAL)&CEnglish::eat };
(4)Person.h/cpp
Person.h
#pragma once #includeclass CPerson;//向前声明 //定义一个函数指针 typedef void(CPerson::*PEN_VIRTUAL)(); class CPerson { public: CPerson() { m_pVirTable = m_Table; } ~CPerson() { } void speak() { printf("Just Speak!"); } void eat() { printf("Just Eat!"); } //模拟虚表指针(数组的指针) PEN_VIRTUAL* m_pVirTable;//PEN_VIRTUAL代表函数指针 //静态成员来表示真正的虚表,用来表示同一个类的虚表是一样的 static PEN_VIRTUAL m_Table[2]; };
Person.cpp
#include "Person.h"
PEN_VIRTUAL CPerson::m_Table[2] = {&CPerson::speak,&CPerson::eat};
(5)testCPP.cpp
#include#include "Person.h" #include "English.h" #include "Chinese.h" int main(int argc,char* argv[]) { CPerson* pPer[2]; CPerson per; CChinese chs; int nChsLength = sizeof(chs); CEnglish eng; int nEngLength = sizeof(chs); //把子类指针转给父类 pPer[0] = &chs; pPer[1] = ŋ for (int i = 0; i < 2; i++) { //(pPer[i]->*pPer[i]->m_pVirTable[0])();//获取虚表指针,等效为下面几步 //等价于: //(1)找到对象头部四个字节--虚表 PEN_VIRTUAL* pVirTable = pPer[i]->m_pVirTable; //(2)根据虚函数的位置(在cpp中定义的顺序),确定该虚函数在虚表的下标 PEN_VIRTUAL pfn = pVirTable[1]; //(3)找到对应的虚函数地址,直接调用该地址 //pPer[i]->speak();//间接调用 (pPer[i]->*pfn)(); printf("rn"); } return 0; }
4.运行结果



