zoukankan      html  css  js  c++  java
  • 在类有成员变量的场景下, 按照虚表原理, 模拟虚函数实现

    前言

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

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

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

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

    模拟虚函数实现的用途

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

    效果

    工程下载点

    编译环境: vc6sp6 + win7x64

    实现概览

    [cpp] view plaincopy
     
    1. /// @file 2015_1218exam_1_7_3exam_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
  • 相关阅读:
    图像处理——灰度化、二值化、膨胀算法、腐蚀算法以及开运算和闭运算
    HDU-4902-Nice boat
    虚拟化之vmware-vsphere概念,原理,功能
    java实现第四届蓝桥杯黄金连分数
    java实现第四届蓝桥杯黄金连分数
    java实现第四届蓝桥杯黄金连分数
    java实现第四届蓝桥杯黄金连分数
    java实现第四届蓝桥杯振兴中华
    java实现第四届蓝桥杯振兴中华
    java实现第四届蓝桥杯振兴中华
  • 原文地址:https://www.cnblogs.com/findumars/p/5174318.html
Copyright © 2011-2022 走看看