宏定义中的#,##和C++中的虚函数表问题

    前几天,有个同学问我宏定义中的#和##都是什么意思啊,说实话,我也不知道,不知道怎么办,google啊!说实话,自己过去对宏定义还真没有深入了解,只会使用最简单的宏定义,自从学了C++之后,基本上都不用宏定义了,用const来直接取代了,《C++ Primer》里也强烈推荐用const来取代宏定义。

    关于宏定义的具体深入介绍,我也不想多说什么,想看的,请前往这个网址,个人感觉讲得挺好: http://learn.akae.cn/media/ch21s02.html 。不过在这里就事论事,只简单地讨论下#和##。

    一句话:# —— 字符串,##——连接两个参数。如果这样写你还不明白,那么就看下面这个例子吧:

   1: #include <iostream>
   2: using namespace std;
   3:  
   4: #define TEST(pid) (cout<<para##pid<<endl);
   5: #define TEST2(p) (cout<<#p<<endl);
   6: int main()
   7: {
   8:     int para3 = 3;
   9:     int para2 = 2;
  10:     TEST(2);    //<==>cout<<para2<<endl;
  11:     TEST(3);    //<==>cout<<para3<<endl;
  12:  
  13:     TEST2(test)        //<==>cout<<"test"<<endl;
  14:     TEST2("test2");    //<==>cout<<""test2""<<endl;
  15:     return 0;
  16: }

    运行的结果如下图所示:

image

    现在,应该明白了吧,感觉很神奇!!!

--------------------------------------------------------------------------------------------------------------华丽的分割线-----------------------------------------------------------------------------------------------------------------------

    接下来再说说C++中的虚函数表吧

    前一段时间,还有一学弟问我一虚函数表的问题,当初学的时候,大体看过,不过这么长时间没用C++了,快要忘记了。这里说一下。当时他问我的问题的大体代码如下:

   1: #include <iostream>
   2: using namespace std;
   3:  
   4: class Base { 
   5: public: 
   6: virtual void f() { cout << "Base::f" << endl; } 
   7: virtual void g() { cout << "Base::g" << endl; } 
   8: virtual void h() { cout << "Base::h" << endl; } 
   9: }; 
  10:  
  11: int main()
  12: {
  13:     typedef void(*Fun)(void); Base b; 
  14:     Fun pFun = NULL; 
  15:     cout << "虚函数表地址:" << (int*)(&b) << endl; 
  16:     cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl; 
  17:     // Invoke the first virtual function 
  18:     pFun = (Fun)*((int*)*(int*)(&b)); 
  19:     pFun(); 
  20: }

运行结果如下:

image

    他不明白的是为什么第一个cout和第二个cout的结果不一样。其实说白了,按我自己的理解,如果你的类中的虚函数,那么在编译的时候,编译器会自动地在类中添加一个成员变量,这个成员变量位于类中所有成员的前面,所以指向这个类的对象的指针同时也是指向这个成员变量的指针,所以第一个cout的结果也就很自然而然了。同时,这个成员变量的内容指向内存中存放这个类所属的虚函数表的地址。所以我们对第二个cout进行一下解析。首先看(int)(&b),很简单,就是取b的地址,同时将其地址由Base*类型强制转换成int类型的指针,再加一个*,就是取这个指针所指向的内存的内容,也就是这个类的虚函数表的第一个函数的地址。再接下来我也不是能很清楚地解释出来,按我自己的理解,就是前面得到了一个地址,如果直接输出,就是一个十进制数,再加上(int *)之后,就是将这个十进制数强制转换成指针类型,而我常用十六进制表示内存位置,所以输出的就是原地址的十六进制表示。以上只是我个人的理解,如有不正确,请指出。

    同时,通过这个实例我也发现,将一个十进制数转换成16进制数,最简单的办法就是将其强制转换成(int *),然后再输出,比如“cout<<(int *)10<<endl;”,输出的结果是0xa。

posted @ 2009-11-24 10:22  陆止于此 海始于斯  阅读(470)  评论(0编辑  收藏  举报