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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现相关的知识,希望对你有一定的参考价值。

前言

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

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

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

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

模拟虚函数实现的用途

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

效果

技术分享

工程下载点

编译环境: vc6sp6 + win7x64

实现概览

[cpp] view plaincopy
 
  1. /// @file \2015_1218\exam_1_7_3\exam_x_x.cpp  
  2. /// @brief exam_1_7_3 用最接近虚表实现原理的方法实现虚表模拟  
  3.   
  4. /** 
  5. 2.模拟虚函数 
  6.  
  7.   不能使用virtual关键字 ,模拟虚函数来表现出多态性: 
  8.    
  9.     写一基类Person   有sayHello,sayGoodbye函数 
  10.      
  11.       有一子类student 它也有自己的sayHello, sayGoodbye函数 
  12.        
  13.         请在这两个类里加入函数 vsayHello, vsayGoodbye函数 
  14.          
  15.           来表现出对象的多态性(分别调用自己的对应的sayHello和sayGoodbye) 
  16.            
  17. 分别使用静态成员函数指针,和成员函数指针完成 
  18. */  
  19.   
  20. #include <iostream>  
  21. #include <limits>  
  22. #include "Person.h"  
  23. #include "student.h"  
  24.   
  25. using namespace std;  
  26.   
  27. void clear_cin();  
  28. void fnTestPolymorphismSimulation();  
  29.   
  30. int main(int argc, char** argv, char** envp)  
  31. {  
  32.     fnTestPolymorphismSimulation();  
  33.   
  34.     cout << "END, press any key to quit" << endl;  
  35.     clear_cin();  
  36.     getchar();  
  37.   
  38.     return 0;  
  39. }  
  40.   
  41. void fnTestPolymorphismSimulation()  
  42. {  
  43.     Person per;  
  44.     student stu;  
  45.     Person* pAry[2] = {new Person(), new student()};  
  46.     size_t nIndex = 0;  
  47.   
  48.     for (nIndex = 0; nIndex < (sizeof(pAry) / sizeof(pAry[0])); nIndex++)  
  49.     {  
  50.         pAry[nIndex]->SetId(3 + nIndex);  
  51.     }  
  52.   
  53.     per.SetId(1);  
  54.     per.vsayHello();  
  55.     per.vsayGoodbye();  
  56.   
  57.     stu.SetId(2);  
  58.     stu.vsayHello();  
  59.     stu.vsayGoodbye();  
  60.   
  61.     for (nIndex = 0; nIndex < (sizeof(pAry) / sizeof(pAry[0])); nIndex++)  
  62.     {  
  63.         pAry[nIndex]->vsayHello();  
  64.         pAry[nIndex]->vsayGoodbye();  
  65.   
  66.         delete pAry[nIndex];  
  67.         pAry[nIndex] = NULL;  
  68.     }  
  69. }  
  70.   
  71. void clear_cin()  
  72. {  
  73.     cin.clear();  
  74.     cin.sync();  
  75. }  

[cpp] view plaincopy
 
  1. // Person.h: interface for the Person class.  
  2. //  
  3. //////////////////////////////////////////////////////////////////////  
  4.   
  5. #if !defined(AFX_PERSON_H__41F1DC26_8E95_4D75_811A_4B84F81E069E__INCLUDED_)  
  6. #define AFX_PERSON_H__41F1DC26_8E95_4D75_811A_4B84F81E069E__INCLUDED_  
  7.   
  8. #if _MSC_VER > 1000  
  9. #pragma once  
  10. #endif // _MSC_VER > 1000  
  11.   
  12. /// 类命名Person, 要和需求一致!  
  13. class Person  
  14. {  
  15. public:  
  16.     enum   
  17.     {  
  18.         e_MemberFnAry_index_destructor = 0,  
  19.         e_MemberFnAry_index_sayHello,  
  20.         e_MemberFnAry_index_sayGoodbye,  
  21.         e_MemberFnAry_index_Last_NULL,  
  22.         e_MemberFnAry_size  
  23.     };  
  24.     typedef void (Person::*PFN_memberFn)();  
  25.   
  26. public:  
  27.     Person();  
  28.     ~Person(); ///< 不能为 virtual, 暂时无法在自定义的虚表中替换析构的地址  
  29.   
  30.     void sayHello();  
  31.     void sayGoodbye();  
  32.   
  33.     void vsayHello();  
  34.     void vsayGoodbye();  
  35.   
  36.     void SetId(int nId) {m_nId = nId;}  
  37.     size_t GetId() {return m_nId;}  
  38.   
  39. private:  
  40.     void OverloadVirtualTable(); ///< 覆盖本类虚表  
  41.     void SetMemberFn(size_t nIndex, PFN_memberFn pFn);  
  42.     PFN_memberFn* getVirtualTable_by_member();  
  43.     PFN_memberFn* getVirtualTable_by_this();  
  44.   
  45.     /// 同一个类的对象虚表相同, 可以用静态成员函数指针数组代替  
  46.     /// 在构造和析构时, 覆盖本对象虚表  
  47.     /// 本类2个虚函数, 一个NULL  
  48.     static PFN_memberFn m_pfnMemberFnAry[e_MemberFnAry_size];  
  49.   
  50.     /// 如果要加入非静态成员变量, 需要定义虚表入口地址  
  51.     size_t m_nAddrVirtualTableEntry; ///< 虚表入口地址  
  52.     size_t m_nId;  
  53. };  
  54.   
  55. #endif // !defined(AFX_PERSON_H__41F1DC26_8E95_4D75_811A_4B84F81E069E__INCLUDED_)  

[cpp] view plaincopy
 
  1. // student.h: interface for the student class.  
  2. //  
  3. //////////////////////////////////////////////////////////////////////  
  4.   
  5. #if !defined(AFX_STUDENT_H__1A031AB4_8639_4C38_9A9A_6DE4095CD7CA__INCLUDED_)  
  6. #define AFX_STUDENT_H__1A031AB4_8639_4C38_9A9A_6DE4095CD7CA__INCLUDED_  
  7.   
  8. #if _MSC_VER > 1000  
  9. #pragma once  
  10. #endif // _MSC_VER > 1000  
  11.   
  12. #include "Person.h"  
  13.   
  14. class student : public Person    
  15. {  
  16. public:  
  17.     enum   
  18.     {  
  19.         e_MemberFnAry_index_destructor = 0,  
  20.         e_MemberFnAry_index_sayHello,  
  21.         e_MemberFnAry_index_sayGoodbye,  
  22.         e_MemberFnAry_index_Last_NULL,  
  23.         e_MemberFnAry_size  
  24.     };  
  25.     typedef void (student::*PFN_memberFn)();  
  26.   
  27. public:  
  28.     student();  
  29.     ~student(); ///< 不能为 virtual, 暂时无法在自定义的虚表中替换析构的地址  
  30.   
  31.     void sayHello();  
  32.     void sayGoodbye();  
  33.   
  34.     void vsayHello();  
  35.     void vsayGoodbye();  
  36.   
  37. private:  
  38.     void OverloadVirtualTable(); ///< 覆盖本类虚表  
  39.     void SetMemberFn(size_t nIndex, PFN_memberFn pFn);  
  40.     PFN_memberFn* getVirtualTable_by_member();  
  41.     PFN_memberFn* getVirtualTable_by_this();  
  42.       
  43.     /// 同一个类的对象虚表相同, 可以用静态成员函数指针数组代替  
  44.     /// 在构造和析构时, 覆盖本对象虚表  
  45.     /// 本类2个虚函数, 一个NULL  
  46.     static PFN_memberFn m_pfnMemberFnAry[e_MemberFnAry_size];  
  47. };  
  48.   
  49. #endif // !defined(AFX_STUDENT_H__1A031AB4_8639_4C38_9A9A_6DE4095CD7CA__INCLUDED_)  

[cpp] view plaincopy
 
  1. // Person.cpp: implementation of the Person class.  
  2. //  
  3. //////////////////////////////////////////////////////////////////////  
  4.   
  5. #include <iostream>  
  6. #include "Person.h"  
  7.   
  8. using namespace std;  
  9.   
  10. //////////////////////////////////////////////////////////////////////  
  11. // Construction/Destruction  
  12. //////////////////////////////////////////////////////////////////////  
  13.   
  14. Person::PFN_memberFn Person::m_pfnMemberFnAry[e_MemberFnAry_size];  
  15. Person::Person()  
  16. :m_nId(-1)  
  17. {  
  18.     OverloadVirtualTable();  
  19. }  
  20.   
  21. Person::~Person()  
  22. {  
  23.     OverloadVirtualTable();  
  24. }  
  25.   
  26. void Person::OverloadVirtualTable()  
  27. {  
  28.     /// 虚表项赋值  
  29.     SetMemberFn(e_MemberFnAry_index_sayHello, &Person::sayHello);  
  30.     SetMemberFn(e_MemberFnAry_index_sayGoodbye, &Person::sayGoodbye);  
  31.     SetMemberFn(e_MemberFnAry_index_Last_NULL, NULL);  
  32.   
  33.     /// 覆盖虚表入口地址  
  34.     (*(int*)this) = (int)getVirtualTable_by_member();  
  35. }  
  36.   
  37. Person::PFN_memberFn* Person::getVirtualTable_by_member()  
  38. {  
  39.     return m_pfnMemberFnAry;  
  40. }  
  41.   
  42. Person::PFN_memberFn* Person::getVirtualTable_by_this()  
  43. {  
  44.     return (Person::PFN_memberFn*)(*(int*)this);  
  45. }  
  46.   
  47. void Person::SetMemberFn(size_t nIndex, PFN_memberFn pFn)  
  48. {  
  49.     size_t nSizeAry = sizeof(m_pfnMemberFnAry) / sizeof(m_pfnMemberFnAry[0]);  
  50.   
  51.     if (nIndex < nSizeAry)  
  52.     {  
  53.         m_pfnMemberFnAry[nIndex] = pFn;  
  54.     }  
  55. }  
  56.   
  57. void Person::sayHello()  
  58. {  
  59.     cout << "void Person::sayHello()" << " m_nId(" << GetId() << ")" << endl;  
  60. }  
  61.   
  62. void Person::sayGoodbye()  
  63. {  
  64.     cout << "void Person::sayGoodbye()" << " m_nId(" << GetId() << ")" << endl;  
  65. }  
  66.   
  67. void Person::vsayHello()  
  68. {  
  69.     PFN_memberFn* pFnAry = getVirtualTable_by_this();  
  70.       
  71.     if (NULL != pFnAry)  
  72.     {  
  73.         (this->*(pFnAry[e_MemberFnAry_index_sayHello]))();      
  74.     }  
  75. }  
  76.   
  77. void Person::vsayGoodbye()  
  78. {  
  79.     PFN_memberFn* pFnAry = getVirtualTable_by_this();  
  80.       
  81.     if (NULL != pFnAry)  
  82.     {  
  83.         (this->*(pFnAry[e_MemberFnAry_index_sayGoodbye]))();      
  84.     }  
  85. }  

[cpp] view plaincopy
 
  1. // student.cpp: implementation of the student class.  
  2. //  
  3. //////////////////////////////////////////////////////////////////////  
  4.   
  5. #include <iostream>  
  6. #include "student.h"  
  7.   
  8. using namespace std;  
  9.   
  10. //////////////////////////////////////////////////////////////////////  
  11. // Construction/Destruction  
  12. //////////////////////////////////////////////////////////////////////  
  13.   
  14. student::PFN_memberFn student::m_pfnMemberFnAry[e_MemberFnAry_size];  
  15. student::student()  
  16. {  
  17.     OverloadVirtualTable();  
  18. }  
  19.   
  20. student::~student()  
  21. {  
  22.     OverloadVirtualTable();  
  23. }  
  24.   
  25. void student::OverloadVirtualTable()  
  26. {  
  27.     /// 虚表项赋值  
  28.     SetMemberFn(e_MemberFnAry_index_sayHello, (PFN_memberFn)&student::sayHello);  
  29.     SetMemberFn(e_MemberFnAry_index_sayGoodbye, (PFN_memberFn)&student::sayGoodbye);  
  30.     SetMemberFn(e_MemberFnAry_index_Last_NULL, NULL);  
  31.       
  32.     /// 覆盖虚表入口地址  
  33.     (*(int*)this) = (int)getVirtualTable_by_member();  
  34. }  
  35.   
  36. void student::SetMemberFn(size_t nIndex, PFN_memberFn pFn)  
  37. {  
  38.     size_t nSizeAry = sizeof(m_pfnMemberFnAry) / sizeof(m_pfnMemberFnAry[0]);  
  39.       
  40.     if (nIndex < nSizeAry)  
  41.     {  
  42.         m_pfnMemberFnAry[nIndex] = pFn;  
  43.     }  
  44. }  
  45.   
  46. void student::sayHello()  
  47. {  
  48.     cout << "void student::sayHello()" << " m_nId(" << GetId() << ")" << endl;  
  49. }  
  50.   
  51. void student::sayGoodbye()  
  52. {  
  53.     cout << "void student::sayGoodbye()" << " m_nId(" << GetId() << ")" << endl;  
  54. }  
  55.   
  56. void student::vsayHello()  
  57. {  
  58.     PFN_memberFn* pFnAry = getVirtualTable_by_this();  
  59.   
  60.     if (NULL != pFnAry)  
  61.     {  
  62.         (this->*(pFnAry[e_MemberFnAry_index_sayHello]))();      
  63.     }  
  64. }  
  65.   
  66. void student::vsayGoodbye()  
  67. {  
  68.     PFN_memberFn* pFnAry = getVirtualTable_by_this();  
  69.       
  70.     if (NULL != pFnAry)  
  71.     {  
  72.         (this->*(pFnAry[e_MemberFnAry_index_sayGoodbye]))();      
  73.     }  
  74. }  
  75.   
  76. student::PFN_memberFn* student::getVirtualTable_by_member()  
  77. {  
  78.     return m_pfnMemberFnAry;  
  79. }  
  80.   
  81. student::PFN_memberFn* student::getVirtualTable_by_this()  
  82. {  
  83.     return (student::PFN_memberFn*)(*(int*)this);  
  84. }  
http://blog.csdn.net/lostspeed/article/details/50379125
http://download.csdn.net/detail/lostspeed/9371924

以上是关于在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现的主要内容,如果未能解决你的问题,请参考以下文章

一元仿函数可以有成员变量吗?

定义一个外部类Father,有成员变量name并赋一个初值。

编写程序,模拟银行存取款业务。 (1)建银行账户类bank,有成员:储户现有款项account(int型)和

Servlet和Struts2的线程安全问题

创建一个Point类,有成员变量x,y,方法getX(),setX(),还有一个构造方 法初始化x和y。创建类主类A来测试它。

FastThreadLocal