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

前言

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

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

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

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

模拟虚函数实现的用途

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

效果

工程下载点

编译环境: vc6sp6 + win7x64

src_PolymorphismSimulation.zip

实现概览

[cpp] view plaincopy

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

[cpp] view plaincopy

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

[cpp] view plaincopy

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

http://blog.csdn.net/lostspeed/article/details/50379125

http://download.csdn.net/detail/lostspeed/9371924

时间: 2024-08-09 19:22:18

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

类的成员变量和属性描述

0x 01 .类的属性 property 类的属性即是通过@property声明的属性.属性是类型为objc_property的一个结构体.该结构体封装了属性的信息 比如属性的名字,属性的类型,属性的可读写,非原子/原子属性等. 1).获取一个类的属性列表方法:OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)入参是一个类的class对象,一个是用于统计属性数量的整形数的地址

【IOS 开发】Object - C 面向对象 - 类 , 对象 , 成员变量 , 成员方法

. 一. 类定义 类定义需要实现两部分 : -- 接口部分 : 定义类的成员变量和方法, 方法是抽象的, 在头文件中定义; -- 实现部分 : 引入接口部分的头文件, 实现抽象方法; 1. 接口部分定义 (1) 接口部分定义格式 接口部分定义格式 : @interface className : superClassName { type _variableName; ... ... } - (type) methodName : type parameterName; @end -- 接口定义

fielderror里的fieldName代表的是jsp里的fieldName还是Action类的成员变量?(待解答)

1.值栈的Action对象中会有一个fielderror属性,代表着字段错误. fielderror是Map<String,List<String>>类型 例如下面的值栈里可看到,fielderror属性里有Map, 键:ppt 值:[^The file is too large to be uploaded:ppt "FuzzyOpinionFigure1.fig" "upload_4fd387d7_8e03_479e_bf04_08e69368e3

解决&quot;VC6.0的ClassView里不能显示类或成员变量&quot;问题

VC6.0是微软1998年发布的,是一款很经典的编辑器,然而它有几个很常见的bug,比如, .cpp文件打不开,智能提示出现异常,这里介绍"VC6.0的ClassView里不能显示类或成员变量"问题的解决方法.详细步骤如下: 1) 关闭VC6.0,找到工程目录里的.clw文件,按Del键删除该 .clw文件,如图(1)所示: 图(1)按Del键删除.clw文件 2)打开VC6.0里的工程,按Ctrl+W –> OK,如图(2).图(3).图(4)所示: 图(2)点击"是

JavaSE8基础 final修饰类的成员变量,其只可以被访问,不能被修改

os :windows7 x64    jdk:jdk-8u131-windows-x64    ide:Eclipse Oxygen Release (4.7.0)        代码: /* final 修饰类的成员变量. 这个变量可以被访问,但是不能被修改.因为这个变量相当于常量. */ class Son { public final int num = 1; } class Demo { public static void main(String[] agrs) { Son s =

获取类的成员变量(ios)

获取类的成员变量(ios) unsigned int numIvars; Ivar *vars = class_copyIvarList(NSClassFromString(@"TestView"), &numIvars); NSString *key=nil; for(int i = 0; i < numIvars; i++) { Ivar thisIvar = vars[i]; key = [NSString stringWithUTF8String:ivar_get

类作为成员变量

声明定义一个类的时候,成员变量的类型经常有int,String等,其实看源码知道String也是一个类: 说明是可以用类作为成员变量的: 其中,构造方法用于创建对象时候调用,new的时候jvm默认调用,可以直接new无参的(人),也可以直接new有参赋值的(小明——身高体重等): 类作为成员变量时候,在成员方法中必须要用这个类变量点它的属性来用,不能直接用,直接用是在栈内存中的一个地址值: set/get方法用于调用赋值或者获取值: 原文地址:https://www.cnblogs.com/wm

C++类中成员变量的初始化总结

1. 普通的变量:      一般不考虑啥效率的情况下 可以在构造函数中进行赋值.考虑一下效率的可以再构造函数的初始化列表中进行. 1 class CA  2 {  3 public:  4      int data;  5 public:  6      CA();  7 };  8     9 CA::CA():data(0) //……#1……初始化列表方式 10 { 11     //data = 0;//……#1……赋值方式 12 }; 2.static 静态变量:       sta

Lesson 04:类和对象,类的成员变量、成员方法、构造方法

1 类(class) java是面向对象程序设计(OPP),类是构造对象的模板或者蓝图.由类构造(construst)对象的过程称为创建类的实例(instance).类的构成: 1 package 包名 2 class 类名 extends 父类名 implements 接口名{ 3 成员变量: 4 构造方法: 5 成员方法: 6 } 7 //一个简化的类的结构 成员变量 成员方法:包含返回值类型.参数列表.方法主体等要素 (1)方法的声明: 1 //方法的声明没有函数体 2 public in