在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现

前言

当类没有成员变量的情况下,   类首地址有4个字节的空间, 这里可以放我们模拟出来的虚表入口地址.

当类有成员变量的情况下, 类首地址就是成员变量,  所以, 为了模拟虚表实现, 需要在成员变量前, 再定义一个int型变量, 用来存放模拟的虚表入口地址.

现在还得不到虚析构函数的地址, 暂时按照非虚析构函数进行模拟.

这个实验是在C++中模拟的.

模拟虚函数实现的用途

在非OOP语言(C语言)中, 模拟类的实现, 可以实现虚函数的效果.

效果

在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现_第1张图片

工程下载点

编译环境: vc6sp6 + win7x64
src_PolymorphismSimulation.zip

实现概览

/// @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);
}





你可能感兴趣的:(在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现)