在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现相关的知识,希望对你有一定的参考价值。
前言
当类没有成员变量的情况下, 类首地址有4个字节的空间, 这里可以放我们模拟出来的虚表入口地址.
当类有成员变量的情况下, 类首地址就是成员变量, 所以, 为了模拟虚表实现, 需要在成员变量前, 再定义一个int型变量, 用来存放模拟的虚表入口地址.
现在还得不到虚析构函数的地址, 暂时按照非虚析构函数进行模拟.
这个实验是在C++中模拟的.
模拟虚函数实现的用途
在非OOP语言(C语言)中, 模拟类的实现, 可以实现虚函数的效果.
效果
工程下载点
编译环境: vc6sp6 + win7x64
实现概览
- /// @file \2015_1218\exam_1_7_3\exam_x_x.cpp
- /// @brief exam_1_7_3 用最接近虚表实现原理的方法实现虚表模拟
- /**
- 2.模拟虚函数
- 不能使用virtual关键字 ,模拟虚函数来表现出多态性:
- 写一基类Person 有sayHello,sayGoodbye函数
- 有一子类student 它也有自己的sayHello, sayGoodbye函数
- 请在这两个类里加入函数 vsayHello, vsayGoodbye函数
- 来表现出对象的多态性(分别调用自己的对应的sayHello和sayGoodbye)
- 分别使用静态成员函数指针,和成员函数指针完成
- */
- #include <iostream>
- #include <limits>
- #include "Person.h"
- #include "student.h"
- using namespace std;
- void clear_cin();
- void fnTestPolymorphismSimulation();
- int main(int argc, char** argv, char** envp)
- {
- fnTestPolymorphismSimulation();
- cout << "END, press any key to quit" << endl;
- clear_cin();
- getchar();
- return 0;
- }
- void fnTestPolymorphismSimulation()
- {
- Person per;
- student stu;
- Person* pAry[2] = {new Person(), new student()};
- size_t nIndex = 0;
- for (nIndex = 0; nIndex < (sizeof(pAry) / sizeof(pAry[0])); nIndex++)
- {
- pAry[nIndex]->SetId(3 + nIndex);
- }
- per.SetId(1);
- per.vsayHello();
- per.vsayGoodbye();
- stu.SetId(2);
- stu.vsayHello();
- stu.vsayGoodbye();
- for (nIndex = 0; nIndex < (sizeof(pAry) / sizeof(pAry[0])); nIndex++)
- {
- pAry[nIndex]->vsayHello();
- pAry[nIndex]->vsayGoodbye();
- delete pAry[nIndex];
- pAry[nIndex] = NULL;
- }
- }
- void clear_cin()
- {
- cin.clear();
- cin.sync();
- }
- // Person.h: interface for the Person class.
- //
- //////////////////////////////////////////////////////////////////////
- #if !defined(AFX_PERSON_H__41F1DC26_8E95_4D75_811A_4B84F81E069E__INCLUDED_)
- #define AFX_PERSON_H__41F1DC26_8E95_4D75_811A_4B84F81E069E__INCLUDED_
- #if _MSC_VER > 1000
- #pragma once
- #endif // _MSC_VER > 1000
- /// 类命名Person, 要和需求一致!
- class Person
- {
- public:
- enum
- {
- e_MemberFnAry_index_destructor = 0,
- e_MemberFnAry_index_sayHello,
- e_MemberFnAry_index_sayGoodbye,
- e_MemberFnAry_index_Last_NULL,
- e_MemberFnAry_size
- };
- typedef void (Person::*PFN_memberFn)();
- public:
- Person();
- ~Person(); ///< 不能为 virtual, 暂时无法在自定义的虚表中替换析构的地址
- void sayHello();
- void sayGoodbye();
- void vsayHello();
- void vsayGoodbye();
- void SetId(int nId) {m_nId = nId;}
- size_t GetId() {return m_nId;}
- private:
- void OverloadVirtualTable(); ///< 覆盖本类虚表
- void SetMemberFn(size_t nIndex, PFN_memberFn pFn);
- PFN_memberFn* getVirtualTable_by_member();
- PFN_memberFn* getVirtualTable_by_this();
- /// 同一个类的对象虚表相同, 可以用静态成员函数指针数组代替
- /// 在构造和析构时, 覆盖本对象虚表
- /// 本类2个虚函数, 一个NULL
- static PFN_memberFn m_pfnMemberFnAry[e_MemberFnAry_size];
- /// 如果要加入非静态成员变量, 需要定义虚表入口地址
- size_t m_nAddrVirtualTableEntry; ///< 虚表入口地址
- size_t m_nId;
- };
- #endif // !defined(AFX_PERSON_H__41F1DC26_8E95_4D75_811A_4B84F81E069E__INCLUDED_)
- // student.h: interface for the student class.
- //
- //////////////////////////////////////////////////////////////////////
- #if !defined(AFX_STUDENT_H__1A031AB4_8639_4C38_9A9A_6DE4095CD7CA__INCLUDED_)
- #define AFX_STUDENT_H__1A031AB4_8639_4C38_9A9A_6DE4095CD7CA__INCLUDED_
- #if _MSC_VER > 1000
- #pragma once
- #endif // _MSC_VER > 1000
- #include "Person.h"
- class student : public Person
- {
- public:
- enum
- {
- e_MemberFnAry_index_destructor = 0,
- e_MemberFnAry_index_sayHello,
- e_MemberFnAry_index_sayGoodbye,
- e_MemberFnAry_index_Last_NULL,
- e_MemberFnAry_size
- };
- typedef void (student::*PFN_memberFn)();
- public:
- student();
- ~student(); ///< 不能为 virtual, 暂时无法在自定义的虚表中替换析构的地址
- void sayHello();
- void sayGoodbye();
- void vsayHello();
- void vsayGoodbye();
- private:
- void OverloadVirtualTable(); ///< 覆盖本类虚表
- void SetMemberFn(size_t nIndex, PFN_memberFn pFn);
- PFN_memberFn* getVirtualTable_by_member();
- PFN_memberFn* getVirtualTable_by_this();
- /// 同一个类的对象虚表相同, 可以用静态成员函数指针数组代替
- /// 在构造和析构时, 覆盖本对象虚表
- /// 本类2个虚函数, 一个NULL
- static PFN_memberFn m_pfnMemberFnAry[e_MemberFnAry_size];
- };
- #endif // !defined(AFX_STUDENT_H__1A031AB4_8639_4C38_9A9A_6DE4095CD7CA__INCLUDED_)
- // Person.cpp: implementation of the Person class.
- //
- //////////////////////////////////////////////////////////////////////
- #include <iostream>
- #include "Person.h"
- using namespace std;
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- Person::PFN_memberFn Person::m_pfnMemberFnAry[e_MemberFnAry_size];
- Person::Person()
- :m_nId(-1)
- {
- OverloadVirtualTable();
- }
- Person::~Person()
- {
- OverloadVirtualTable();
- }
- void Person::OverloadVirtualTable()
- {
- /// 虚表项赋值
- SetMemberFn(e_MemberFnAry_index_sayHello, &Person::sayHello);
- SetMemberFn(e_MemberFnAry_index_sayGoodbye, &Person::sayGoodbye);
- SetMemberFn(e_MemberFnAry_index_Last_NULL, NULL);
- /// 覆盖虚表入口地址
- (*(int*)this) = (int)getVirtualTable_by_member();
- }
- Person::PFN_memberFn* Person::getVirtualTable_by_member()
- {
- return m_pfnMemberFnAry;
- }
- Person::PFN_memberFn* Person::getVirtualTable_by_this()
- {
- return (Person::PFN_memberFn*)(*(int*)this);
- }
- void Person::SetMemberFn(size_t nIndex, PFN_memberFn pFn)
- {
- size_t nSizeAry = sizeof(m_pfnMemberFnAry) / sizeof(m_pfnMemberFnAry[0]);
- if (nIndex < nSizeAry)
- {
- m_pfnMemberFnAry[nIndex] = pFn;
- }
- }
- void Person::sayHello()
- {
- cout << "void Person::sayHello()" << " m_nId(" << GetId() << ")" << endl;
- }
- void Person::sayGoodbye()
- {
- cout << "void Person::sayGoodbye()" << " m_nId(" << GetId() << ")" << endl;
- }
- void Person::vsayHello()
- {
- PFN_memberFn* pFnAry = getVirtualTable_by_this();
- if (NULL != pFnAry)
- {
- (this->*(pFnAry[e_MemberFnAry_index_sayHello]))();
- }
- }
- void Person::vsayGoodbye()
- {
- PFN_memberFn* pFnAry = getVirtualTable_by_this();
- if (NULL != pFnAry)
- {
- (this->*(pFnAry[e_MemberFnAry_index_sayGoodbye]))();
- }
- }
- // student.cpp: implementation of the student class.
- //
- //////////////////////////////////////////////////////////////////////
- #include <iostream>
- #include "student.h"
- using namespace std;
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- student::PFN_memberFn student::m_pfnMemberFnAry[e_MemberFnAry_size];
- student::student()
- {
- OverloadVirtualTable();
- }
- student::~student()
- {
- OverloadVirtualTable();
- }
- void student::OverloadVirtualTable()
- {
- /// 虚表项赋值
- SetMemberFn(e_MemberFnAry_index_sayHello, (PFN_memberFn)&student::sayHello);
- SetMemberFn(e_MemberFnAry_index_sayGoodbye, (PFN_memberFn)&student::sayGoodbye);
- SetMemberFn(e_MemberFnAry_index_Last_NULL, NULL);
- /// 覆盖虚表入口地址
- (*(int*)this) = (int)getVirtualTable_by_member();
- }
- void student::SetMemberFn(size_t nIndex, PFN_memberFn pFn)
- {
- size_t nSizeAry = sizeof(m_pfnMemberFnAry) / sizeof(m_pfnMemberFnAry[0]);
- if (nIndex < nSizeAry)
- {
- m_pfnMemberFnAry[nIndex] = pFn;
- }
- }
- void student::sayHello()
- {
- cout << "void student::sayHello()" << " m_nId(" << GetId() << ")" << endl;
- }
- void student::sayGoodbye()
- {
- cout << "void student::sayGoodbye()" << " m_nId(" << GetId() << ")" << endl;
- }
- void student::vsayHello()
- {
- PFN_memberFn* pFnAry = getVirtualTable_by_this();
- if (NULL != pFnAry)
- {
- (this->*(pFnAry[e_MemberFnAry_index_sayHello]))();
- }
- }
- void student::vsayGoodbye()
- {
- PFN_memberFn* pFnAry = getVirtualTable_by_this();
- if (NULL != pFnAry)
- {
- (this->*(pFnAry[e_MemberFnAry_index_sayGoodbye]))();
- }
- }
- student::PFN_memberFn* student::getVirtualTable_by_member()
- {
- return m_pfnMemberFnAry;
- }
- student::PFN_memberFn* student::getVirtualTable_by_this()
- {
- return (student::PFN_memberFn*)(*(int*)this);
- }
http://blog.csdn.net/lostspeed/article/details/50379125
http://download.csdn.net/detail/lostspeed/9371924
以上是关于在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现的主要内容,如果未能解决你的问题,请参考以下文章
定义一个外部类Father,有成员变量name并赋一个初值。
编写程序,模拟银行存取款业务。 (1)建银行账户类bank,有成员:储户现有款项account(int型)和
创建一个Point类,有成员变量x,y,方法getX(),setX(),还有一个构造方 法初始化x和y。创建类主类A来测试它。