当类没有成员变量的情况下, 类首地址有4个字节的空间, 这里可以放我们模拟出来的虚表入口地址.
当类有成员变量的情况下, 类首地址就是成员变量, 所以, 为了模拟虚表实现, 需要在成员变量前, 再定义一个int型变量, 用来存放模拟的虚表入口地址.
现在还得不到虚析构函数的地址, 暂时按照非虚析构函数进行模拟.
这个实验是在C++中模拟的.
在非OOP语言(C语言)中, 模拟类的实现, 可以实现虚函数的效果.
/// @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
#include
#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
#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
#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);
}