本人能力、精力有限,所言所感都基于自身的实践和有限的阅读、查阅,如有错误,欢迎拍砖,敬请赐教——博客园:钱智慧。

在说RTTI之前需要明白c++中类静态成员的初始化特点:类的静态数据成员需要在类体外显式初始化(const 类型的静态数据成员才能在类体内直接初始化)。关于数据(全局变量,局部变量,静态变量,类数据成员)的初始化特点可参考《C++primer》相关章节。

还要知道,类的静态成员的初始化发生于main之前,MFC的RTTI机制正是利用了这一特点,从而在进入main函数之前提前把一个信息链表建立起来,而这个链表每个节点便是一个CruntimeClass对象。那么,在main之前就得把链表构建好,这意味着在main之前就得执行代码,试问:什么代码能在main之前得以执行呢?这便是全局对象或者静态对象的构造函数中的代码。比如,有个全局对象Person p;那么,p的造函数会在main执行之前执行,从而我们可以把一些提前完成的任务放在Person的构造函数里,Person本身甚至完全不重要,我们只是想利用它的构造函数来完成自己想要的功能而已,MFC的RTTI也利用了这一点,比如其中的AFX_CLASSINIT类(结构体),它存在的唯一目的就是为了利用其构造函数往链表中添加节点,再比如接下来的模拟例子中的AFX_ClassNode类也是如此。下面的例子仅仅是模拟了RTTI中构建链表的过程,并不是完整的RTTI机制模拟,没有候捷的模拟复杂,所以更容易看懂,代码如下:

  1. #include <iostream>
  2.  
  3. //链表节点类
  4. struct ClassNode
  5. {
  6. ClassNode* next;
  7. //注意,节点类有个静态指针,因为一个链表只需要有一个首指针
  8. static ClassNode* first;//first本身是Node类的静态数据成员,需要在类体外初始化
  9. };
  10. ClassNode* ClassNode::first=;
  11. //继承体系
  12. /* Fruit
  13. |
  14. -----------
  15. | |
  16. Orange Apple
  17. |
  18. BigApple
  19. */
  20. struct AFX_LISTINIT//这个类的存在只是为了利用其构造函数来给链表增加节点
  21. {
  22. AFX_LISTINIT(ClassNode* pNode)
  23. {
  24. printf("添加一个节点构建链表\n");
  25. pNode->next=ClassNode::first;
  26. ClassNode::first=pNode;
  27. }
  28. };
  29. //Fruit
  30. class Fruit
  31. {
  32. public:
  33. static ClassNode node;
  34. };
  35. //下面两行代码把Fruit的静态数据成员node节点加入链表(此时链表一个节点都没有)
  36. ClassNode Fruit::node={};//Fruit类的指针初始化为0,就是null
  37. AFX_LISTINIT initFruit(&Fruit::node);
  38. //Orange
  39. class Orange:public Fruit
  40. {
  41. public:
  42. static ClassNode node;
  43. };
  44. ClassNode Orange::node={};//Node是结构体,所以可以这样初始化
  45. AFX_LISTINIT initOrange(&Orange::node);
  46. //Apple
  47. class Apple:public Fruit
  48. {
  49. public:
  50. static ClassNode node;
  51. };
  52. ClassNode Apple::node={};
  53. AFX_LISTINIT initApple(&Apple::node);
  54. //BigApple
  55. class BigApple:public Apple
  56. {
  57. public:
  58. static ClassNode node;
  59. };
  60. ClassNode BigApple::node={};
  61. AFX_LISTINIT initBigApple(&BigApple::node);
  62.  
  63. int main()
  64. {
  65. return ;
  66. }

最终可以看到有四句打印语句。

如同MFC中RTTI中的链表一样,本例的链表也是倒着添加节点的,即先添加的节点将会在链表靠后的位置。

引入宏定义:

我们的模拟很简陋,仅仅是模拟出了创建链表的机制,但是这个链表是粗糙的,每个节点几乎没有保存跟特定类相关的信息,比如类名,比如指向基类节点的指针,比如用来创建类实例的函数指针等。而且我们每定义一个新的类,如果想加入链表都需要两句类似的代码:初始化节点,构建一个AFX对象以添加节点,这无疑体力和键盘的消磨,真正的RTTI中用宏避免了手动敲击重复代码,宏并不神秘,代码替换而已。我们一步步完善这个模拟。我们的链表中节点类型是ClassNode,MFC中是CRuntmeClass类型(结构体),而且MFC中每个类的静态数据成员CRuntimeClass对象有不同的名称,格式是:class+类名,比如classOrange,而我们的类中的节点变量名称都叫node,我们就来改进这一点,让每个的节点变量名具备class+类名的格式,利用C语言一种特殊的预处理器语法 a##b得到ab,注意,a和b可以是任意类型的变量名称,通过这种方式可以得到一种新的变量名ab,从而我们的改进方式是:直接将使用node变量名的地方换成class##Fruit,class##Apple,class##Orange……然而这是不行的,因为##语法是预处理器负责的,VC6.0给的错误是:preprocessor command must start as first nonwhite space。这就是在逼着我们用宏定义了,最终改善的代码:

  1. #include <iostream>
  2.  
  3. #define DECLARE_DYNAMIC(class_name) \
  4. public: \
  5. static ClassNode class##class_name;
  6.  
  7. #define IMPLEMENT_DYNAMIC(class_name) \
  8. ClassNode class_name::class##class_name={}; \
  9. AFX_LISTINIT init##class_name(&class_name::class##class_name);
  10.  
  11. //链表节点类
  12. struct ClassNode
  13. {
  14. ClassNode* next;
  15. static ClassNode* first;
  16. };
  17. ClassNode* ClassNode::first=;
  18.  
  19. struct AFX_LISTINIT
  20. {
  21. AFX_LISTINIT(ClassNode* pNode)
  22. {
  23. printf("构建链表:添加一个节点\n");
  24. pNode->next=ClassNode::first;
  25. ClassNode::first=pNode;
  26. }
  27. };
  28. //Fruit
  29. class Fruit
  30. {
  31. DECLARE_DYNAMIC(Fruit)
  32. };
  33. IMPLEMENT_DYNAMIC(Fruit);
  34.  
  35. //Orange
  36. class Orange:public Fruit
  37. {
  38. DECLARE_DYNAMIC(Orange)
  39. };
  40. IMPLEMENT_DYNAMIC(Orange)
  41.  
  42. //Apple
  43. class Apple:public Fruit
  44. {
  45. DECLARE_DYNAMIC(Apple)
  46. };
  47. IMPLEMENT_DYNAMIC(Apple)
  48. //BigApple
  49. class BigApple:public Apple
  50. {
  51. DECLARE_DYNAMIC(BigApple)
  52. };
  53. IMPLEMENT_DYNAMIC(BigApple)
  54.  
  55. int main()
  56. {
  57. return ;
  58. }

引入类名:

  1. #include <iostream>
  2.  
  3. //注意宏定义中的#和##语法,前者可把变量名转成字符串
  4.  
  5. #define DECLARE_DYNAMIC(class_name) \
  6. public: \
  7. static ClassNode class##class_name;
  8.  
  9. #define IMPLEMENT_DYNAMIC(class_name) \
  10. char _sz##class_name[]=#class_name; \
  11. ClassNode class_name::class##class_name={_sz##class_name,}; \
  12. AFX_LISTINIT init##class_name(&class_name::class##class_name);
  13.  
  14. //链表节点类
  15. struct ClassNode
  16. {
  17. char* m_szClassName;
  18. ClassNode* next;
  19. static ClassNode* first;
  20. };
  21. ClassNode* ClassNode::first=;
  22.  
  23. struct AFX_LISTINIT
  24. {
  25. AFX_LISTINIT(ClassNode* pNode)
  26. {
  27. printf("构建链表:添加一个节点:");
  28. printf(pNode->m_szClassName);
  29. printf("\n");
  30. pNode->next=ClassNode::first;
  31. ClassNode::first=pNode;
  32. }
  33. };
  34. //Fruit
  35. class Fruit
  36. {
  37. DECLARE_DYNAMIC(Fruit)
  38. };
  39. IMPLEMENT_DYNAMIC(Fruit);
  40.  
  41. //Orange
  42. class Orange:public Fruit
  43. {
  44. DECLARE_DYNAMIC(Orange)
  45. };
  46. IMPLEMENT_DYNAMIC(Orange)
  47.  
  48. //Apple
  49. class Apple:public Fruit
  50. {
  51. DECLARE_DYNAMIC(Apple)
  52. };
  53. IMPLEMENT_DYNAMIC(Apple)
  54. //BigApple
  55. class BigApple:public Apple
  56. {
  57. DECLARE_DYNAMIC(BigApple)
  58. };
  59. IMPLEMENT_DYNAMIC(BigApple)
  60.  
  61. int main()
  62. {
  63. return ;
  64. }

引入继承关系:

引入继承关系,便是在节点类中增加一个指向父类结点的指针,问题是如何初始这个指针呢,这要求我们必须提供获得某个类的节点指针的方法,从而我们需要定义RUNTIME_CLASS宏,它接收类名,返回类的节点指针。还要注意,终极父类Fruit并没有父类,所以不能像其他类那样对其直接使用实现宏,而是要特殊处理,即把其父类置空(毕竟RUNTIME_CLASS宏不能接收NULL),事实上RUNTIME_CLASS宏与即将实现的GetRuntimClass成员函数功能是一样的,只不过一个是宏,一个是成员函数,只能通过类对象调用。最终代码如下:

  1. #include <iostream>
  2.  
  3. //注意宏定义中的#和##语法,前者可把变量名转成字符串
  4. #define RUNTIME_CLASS(class_name) (&class_name::class##class_name)
  5. #define DECLARE_DYNAMIC(class_name) \
  6. public: \
  7. static ClassNode class##class_name; \
  8. ClassNode* GetRuntimeClass();
  9.  
  10. #define IMPLEMENT_DYNAMIC(class_name,base_class_name) \
  11. char _sz##class_name[]=#class_name; \
  12. ClassNode class_name::class##class_name={RUNTIME_CLASS(base_class_name),_sz##class_name,}; \
  13. AFX_LISTINIT init##class_name(&class_name::class##class_name); \
  14. ClassNode* class_name::GetRuntimeClass(){return &class_name::class##class_name;}
  15.  
  16. //链表节点类
  17. struct ClassNode
  18. {
  19. ClassNode* m_baseClass;
  20. char* m_szClassName;
  21. ClassNode* next;
  22. static ClassNode* first;
  23. };
  24. ClassNode* ClassNode::first=;
  25.  
  26. struct AFX_LISTINIT
  27. {
  28. AFX_LISTINIT(ClassNode* pNode)
  29. {
  30. printf("构建链表:添加一个节点:");
  31. printf(pNode->m_szClassName);
  32. printf("\n");
  33. pNode->next=ClassNode::first;
  34. ClassNode::first=pNode;
  35. }
  36. };
  37. //Fruit
  38. class Fruit
  39. {
  40. DECLARE_DYNAMIC(Fruit)
  41. };
  42. //IMPLEMENT_DYNAMIC(Fruit);特殊处理最终父类,MFC中便是上帝CObject
  43. char _szFruit[]="Fruit";
  44. ClassNode Fruit::classFruit={/*RUNTIME_CLASS(base_class_name)*/NULL,_szFruit,};
  45. AFX_LISTINIT initFruit(&Fruit::classFruit);
  46.  
  47. //Orange
  48. class Orange:public Fruit
  49. {
  50. DECLARE_DYNAMIC(Orange)
  51. };
  52. IMPLEMENT_DYNAMIC(Orange,Fruit)
  53.  
  54. //Apple
  55. class Apple:public Fruit
  56. {
  57. DECLARE_DYNAMIC(Apple)
  58. };
  59. IMPLEMENT_DYNAMIC(Apple,Fruit)
  60. //BigApple
  61. class BigApple:public Apple
  62. {
  63. DECLARE_DYNAMIC(BigApple)
  64. };
  65. IMPLEMENT_DYNAMIC(BigApple,Apple)
  66.  
  67. int main()
  68. {
  69. printf("***********************\n");
  70. //**测试链表中基类信息
  71. //打印出各个类及父类名称
  72. for(ClassNode* cursor=ClassNode::first;cursor!=NULL;)
  73. {
  74. ClassNode * baseClass=cursor->m_baseClass;
  75. if(baseClass!=NULL)
  76. {
  77. printf("%s : %s\n",cursor->m_szClassName,baseClass->m_szClassName);
  78. }
  79. else
  80. {
  81. printf(cursor->m_szClassName);
  82. printf("\n");
  83. }
  84. cursor=cursor->next;
  85. }
  86. printf("***********************\n");
  87. //**用GetRumtimeClass方法测试
  88. //找出ba所属类型的所有祖宗
  89. BigApple ba;
  90. for(ClassNode* findBase=ba.GetRuntimeClass()->m_baseClass;findBase!=NULL;)
  91. {
  92. printf(findBase->m_szClassName);
  93. printf("\n");
  94. findBase=findBase->m_baseClass;
  95. }
  96.  
  97. return ;
  98. }

引入类型识别函数IsKindOf函数:

把IsKindOf定义在根父类Fruit中,这样后代类都能继承到。IsKindOf是一个普通的成员函数,其参数是一个ClassNode指针(MFC中则是CRuntimeClass指针),它的思想很简单:先用本类的ClassNode指针与参数比较,若不相等再用本类的父类的ClassNode指针去比较……一旦相等,便返回真。比较两指针的值是完全没问题的,我们知道,若两指针的值相等,便能说明二者指向同一个对象,此处若两指针相等则说明二者指向同一个ClassNode对象。

尤其要注意的是:之前我们的GetRuntimeClass对象不是虚函数,但到这一步,它必须得是虚函数,因为IsKindOf调用了GetRuntimeClass函数,看代码:

BigApple ba;

printf("%d\n",ba.isKindOf(RUNTIME_CLASS(Apple)));

若没用虚函数,则执行到isKindOf中时,不能做到动态绑定而调用ba自己的GetRuntimeClass函数,从而出现逻辑错误。完整代码:

  1. #include <iostream>
  2.  
  3. //注意宏定义中的#和##语法,前者可把变量名转成字符串
  4. #define RUNTIME_CLASS(class_name) (&class_name::class##class_name)
  5. #define DECLARE_DYNAMIC(class_name) \
  6. public: \
  7. static ClassNode class##class_name; \
  8. virtual ClassNode* GetRuntimeClass();//这里必须是虚函数!!
  9.  
  10. #define IMPLEMENT_DYNAMIC(class_name,base_class_name) \
  11. char _sz##class_name[]=#class_name; \
  12. ClassNode class_name::class##class_name={RUNTIME_CLASS(base_class_name),_sz##class_name,}; \
  13. AFX_LISTINIT init##class_name(&class_name::class##class_name); \
  14. ClassNode* class_name::GetRuntimeClass(){return &class_name::class##class_name;}
  15.  
  16. //链表节点类
  17. struct ClassNode
  18. {
  19. ClassNode* m_baseClass;
  20. char* m_szClassName;
  21. ClassNode* next;
  22. static ClassNode* first;
  23. };
  24. ClassNode* ClassNode::first=;
  25.  
  26. struct AFX_LISTINIT
  27. {
  28. AFX_LISTINIT(ClassNode* pNode)
  29. {
  30. printf("构建链表:添加一个节点:");
  31. printf(pNode->m_szClassName);
  32. printf("\n");
  33. pNode->next=ClassNode::first;
  34. ClassNode::first=pNode;
  35. }
  36. };
  37.  
  38. //Fruit
  39. class Fruit
  40. {
  41. public:
  42. bool isKindOf(ClassNode* pNode);
  43. DECLARE_DYNAMIC(Fruit)
  44. };
  45. //IMPLEMENT_DYNAMIC(Fruit);特殊处理最终父类,MFC中便是上帝CObject
  46. char _szFruit[]="Fruit";
  47. ClassNode Fruit::classFruit={/*RUNTIME_CLASS(base_class_name)*/NULL,_szFruit,};
  48. AFX_LISTINIT initFruit(&Fruit::classFruit);
  49. ClassNode* Fruit::GetRuntimeClass(){return &Fruit::classFruit;}
  50. bool Fruit::isKindOf(ClassNode* pNode)
  51. {
  52. for(ClassNode* cursor=this->GetRuntimeClass();cursor!=NULL;)
  53. {
  54. if(cursor==pNode)
  55. {
  56. return true;
  57. }
  58. cursor=cursor->m_baseClass;
  59. }
  60. return false;
  61. }
  62.  
  63. //Orange
  64. class Orange:public Fruit
  65. {
  66. DECLARE_DYNAMIC(Orange)
  67. };
  68. IMPLEMENT_DYNAMIC(Orange,Fruit)
  69.  
  70. //Apple
  71. class Apple:public Fruit
  72. {
  73. DECLARE_DYNAMIC(Apple)
  74. };
  75. IMPLEMENT_DYNAMIC(Apple,Fruit)
  76. //BigApple
  77. class BigApple:public Apple
  78. {
  79. DECLARE_DYNAMIC(BigApple)
  80. };
  81. IMPLEMENT_DYNAMIC(BigApple,Apple)
  82.  
  83. int main()
  84. {
  85. BigApple ba;
  86. //**测试isKindOf(此处最值得注意的地方便是Fruit类的GetRuntimeClass必须得是虚函数)
  87. printf("%d\n",ba.isKindOf(RUNTIME_CLASS(Apple)));
  88. printf("%d\n",ba.isKindOf(RUNTIME_CLASS(Orange)));
  89.  
  90. return ;
  91. }

另外,本示例代码的全局变量不像候捷的示例代码那样让全局变量都为静态的,这并无大碍,但要明白全局的静态变量只能在本文件中使用,虽然其生命周期是整个程序的运行期,非静态的全局变量才能通过extern声明被外部文件使用,全局函数也是这样。

引入动态创建:

思想就是为每个类加入一个静态的createObject函数,为ClassNode节点加入一个函数指针成员,构建链表时中每个节点时,把指针指向每个类自己的createObject函数,从而将来有了相应类的节点指针(即CRuntimClass指针)便能调用相应的createObject方法。需要注意的是,我们也为ClassNode引入一个普通的成员方法CreateObject,这个方法是将来动态创建时真正要调用的方法,它的存在不过是让功能更优雅一些,其实没有它也可以,不过调用者需要自己判断ClassNode对象里的函数指针是不是为空,不为空才能调用该指针指向的类的静态createObject方法。至今,为了省事,我们的根级父类Fruit定义中一直还有动态声明宏,但这里要把它拿掉而用具体的代码了,因为我们不让Fruit具备动态创建功能,即不给其添加createObject方法,其节点中的m_pfnCreateObject指针也置空。另外为了测试方便,我们给根父类Fruit加入了虚方法sayHello,子类都覆写了这个方法,候捷的的动态创建示例代码中有Load方法,其实它完成的便是本例的main函数代码,候哥这么做是为了契合后续的持久化机制。完整代码:

  1. #include <iostream>
  2.  
  3. //注意宏定义中的#和##语法,前者可把变量名转成字符串
  4. #define RUNTIME_CLASS(class_name) (&class_name::class##class_name)
  5. #define DECLARE_DYNAMIC(class_name) \
  6. public: \
  7. static ClassNode class##class_name; \
  8. virtual ClassNode* GetRuntimeClass(); \
  9. static Fruit* createObject();
  10.  
  11. #define IMPLEMENT_DYNAMIC(class_name,base_class_name) \
  12. char _sz##class_name[]=#class_name; \
  13. ClassNode class_name::class##class_name={class_name::createObject,\
  14. RUNTIME_CLASS(base_class_name),_sz##class_name,}; \
  15. AFX_LISTINIT init##class_name(&class_name::class##class_name); \
  16. ClassNode* class_name::GetRuntimeClass(){return &class_name::class##class_name;} \
  17. Fruit* class_name::createObject() {return new class_name;}
  18.  
  19. //**链表节点类
  20. //提前用到了Fruit类,需要前向声明
  21. class Fruit;
  22. struct ClassNode
  23. {
  24. Fruit* CreateObject();
  25. Fruit* (*m_pfnCreateObject)();
  26. ClassNode* m_baseClass;
  27. char* m_szClassName;
  28. ClassNode* next;
  29. static ClassNode* first;
  30. };
  31. Fruit* ClassNode::CreateObject()
  32. {
  33. if(m_pfnCreateObject==NULL)
  34. {
  35. printf("这个类不支持动态创建\n");
  36. return NULL;
  37. }
  38. return m_pfnCreateObject();
  39. }
  40. ClassNode* ClassNode::first=;
  41.  
  42. struct AFX_LISTINIT
  43. {
  44. AFX_LISTINIT(ClassNode* pNode)
  45. {
  46. printf("构建链表:添加一个节点:");
  47. printf(pNode->m_szClassName);
  48. printf("\n");
  49. pNode->next=ClassNode::first;
  50. ClassNode::first=pNode;
  51. }
  52. };
  53.  
  54. //Fruit
  55. class Fruit
  56. {
  57. public:
  58. virtual void sayHello(){printf("hello Fruit\n");}
  59. bool isKindOf(ClassNode* pNode);
  60. static ClassNode classFruit;
  61. virtual ClassNode* GetRuntimeClass();
  62. };
  63. //IMPLEMENT_DYNAMIC(Fruit);特殊处理最终父类,MFC中便是上帝CObject
  64. char _szFruit[]="Fruit";
  65. ClassNode Fruit::classFruit={NULL,/*RUNTIME_CLASS(base_class_name)*/NULL,_szFruit,};
  66. AFX_LISTINIT initFruit(&Fruit::classFruit);
  67. ClassNode* Fruit::GetRuntimeClass(){return &Fruit::classFruit;}
  68. bool Fruit::isKindOf(ClassNode* pNode)
  69. {
  70. for(ClassNode* cursor=this->GetRuntimeClass();cursor!=NULL;)
  71. {
  72. if(cursor==pNode)
  73. {
  74. return true;
  75. }
  76. cursor=cursor->m_baseClass;
  77. }
  78. return false;
  79. }
  80.  
  81. //Orange
  82. class Orange:public Fruit
  83. {
  84. public:
  85. void sayHello(){printf("hello Orange\n");}
  86. DECLARE_DYNAMIC(Orange)
  87. };
  88. IMPLEMENT_DYNAMIC(Orange,Fruit)
  89.  
  90. //Apple
  91. class Apple:public Fruit
  92. {
  93. public:
  94. void sayHello(){printf("hello Apple\n");}
  95. DECLARE_DYNAMIC(Apple)
  96. };
  97. IMPLEMENT_DYNAMIC(Apple,Fruit)
  98. //BigApple
  99. class BigApple:public Apple
  100. {
  101. public:
  102. void sayHello(){printf("hello BigApple\n");}
  103. DECLARE_DYNAMIC(BigApple)
  104. };
  105. IMPLEMENT_DYNAMIC(BigApple,Apple)
  106.  
  107. int main()
  108. {
  109. //**动态创建测试
  110. char className[];
  111. scanf("%s",&className);
  112. for(ClassNode* cursor=ClassNode::first;cursor!=NULL;)
  113. {
  114. if(strcmp(cursor->m_szClassName,className)==)
  115. {
  116. cursor->CreateObject()->sayHello();
  117. break;
  118. }
  119. cursor=cursor->next;
  120. }
  121. return ;
  122. }

到此,本示例算是完全结束了,为了简单省事,本示例对候哥的例子做了尽可能的简化。

MFC之RTTI与动态创建的更多相关文章

  1. 《深入浅出MFC》系列之动态创建

    /*************************************************************************************************** ...

  2. MFC原理第四讲.动态创建机制

    MFC原理第四讲.动态创建机制 一丶要学习的知识点以及简介 动态创建是什么意思? 动态创建其实就是跟C++的new一样.都是创建对象.但是规避了C++语法的缺陷. 例如: char * ClassNa ...

  3. MFC六大核心机制之三:动态创建

    MFC中很多地方都使用了动态创建技术.动态创建就是在程序运行时创建指定类的对象.例如MFC的单文档程序中,文档模板类的对象就动态创建了框架窗口对象.文档对象和视图对象.动态创建技术对于希望了解MFC底 ...

  4. MFC之动态创建按钮

    打开VS 创建MFC基于对话框的工程,在对话框初始化方法中动态创建一个按钮实例: 1> CButton *pMyButton = new CButton();CEdit *pMyEdit = n ...

  5. MFC动态创建对话框中的按钮控件并创建其响应消息

    转自:http://www.cnblogs.com/huhu0013/p/4626686.html 动态按钮(多个)的创建: 1.在类中声明并定义按钮控件的ID #define IDC_D_BTN 1 ...

  6. 【转载】MFC动态创建控件及其消息响应函数

    原文:http://blog.sina.com.cn/s/blog_4a08244901014ok1.html 这几天专门调研了一下MFC中如何动态创建控件及其消息响应函数. 参考帖子如下: (1)h ...

  7. MFC动态创建控件及其消息响应函数

    这几天专门调研了一下MFC中如何动态创建控件及其消息响应函数. 参考帖子如下: (1)http://topic.csdn.net/u/20101204/13/5f1b1e70-2f1c-4205-ba ...

  8. MFC小程序003------MFC使用WebBrowser组件,在对话框中创建滚动视图,动态创建一个静态文本控件并设置鼠标单击的消息响应

    MFC小程序截图: 一.在MFC中简单使用WebBrowser的ActiveX插件的方法: 见博文:  http://blog.csdn.net/supermanking/article/detail ...

  9. MFC动态创建按钮,并在按钮上实现位图的切换显示

    动态创建按钮,并在按钮中添加位图,通过单击按钮显示不同的位图,可设置为显示按钮按下和弹起两种状态.只要判断a值从而输入不同的响应代码. 1.在头文件中添加: CButton *pBtn; 2.在初始化 ...

随机推荐

  1. 基于Emgu CV 的手势识别实现PPT的控制放映

    Emgu CV 简介         众所周知,Emgu CV是.NET平台下对OpenCV图像处理库的封装,也就是.NET版的OpenCV.开发者可以很方便的通过C#,VB等语言调用OpenCV函数 ...

  2. .net中的Array,ArrayList和List

    Array:任意类型,定长 ArrayList:任意类型,不定长 List:特定类型,不定长 Array和ArrayList是通过存储object类型实现可以存储任意类型数据,使用时需要拆箱和装箱

  3. 用python实现k近邻算法

    用python写程序真的好舒服. code: import numpy as np def read_data(filename): '''读取文本数据,格式:特征1 特征2 -- 类别''' f=o ...

  4. ASP.Net 添加 Interop for Word, excel 插件

    1:在服务器上安装office的Excel软件. 2:在"开始"->"运行"中输入dcomcnfg.exe启动"组件服务" 3:依次双 ...

  5. noj [1482] 嘛~付钱吧!(完全背包)

    http://ac.nbutoj.com/Problem/view.xhtml?id=1482 [1482] 嘛~付钱吧! 时间限制: 1000 ms 内存限制: 65535 K 问题描述 大白菜带着 ...

  6. new 的用法

     在C#中,new关键字有三种用法: 1.new 运算符,用于创建对象和调用构造函数. 2.new  修饰符,在用作修饰符时,new关键字可以显式隐藏从基类继承的成员. 3.new 约束 ,用于在泛型 ...

  7. Seay工具分享

    百度网盘:http://pan.baidu.com/share/home?uk=4045637737&view=share#category/type=0

  8. PHP之序列化与反序列化讲解

    serialize() 把变量和它们的值编码成文本形式 unserialize() 恢复原先变量 eg: $stooges = array('Moe','Larry','Curly');$new = ...

  9. conky 配置变量表

    转自conky 配置变量表 项目主页:http://conky.sourceforge.net/ 文档说明:http://conky.sourceforge.net/docs.html Variabl ...

  10. 当 ITOA 遇上 OneAlert,企业可以至少每年节省 3600 小时!

    每个工作日,一家大型企业都可能存在一两件优先级为 1 级的事件,五六件优先级为 2 级的事件和百来件优先级为 3 级的事件.试想一下,如果公司所有支持人员都要收到每个事件的通知--不想了,我好方!还能 ...