这是一个小小的花园,我就是园丁。我在这里种植些小小的C++之花。每一株都有它自己的色彩,每一株都有特有的芬芳。我小心的栽培着,与朋友们分享着美丽。
第一朵花:NULL的秘密
在C与C++中对NULL的定义是不同的:
#define NULL 0; // C++中对NULL的定义
#define NULL? ((void*)0) // C 中NULL是这样定义的
为什么在这两种语言中会有不同的定义呢?
在C++中指针是强类型的,而在C中则不是。因此,void*在C++中只能通过显式转换来转换为其它类型的指针。如果C++中的NULL按照C中的定义,那么下面的语句
char * p = NULL;
实际上会扩展为:
char * p = (void*) 0; // 编译器将产生错误: incompatible pointer types
这就是两种语言中对NULL作不同定义的原因了。
第二朵花:inline vs. __forceinline
MS Visual C++, 以及其它几种编译器,提供了一个非标准的用于控制函数内嵌(inline)的关键字,作为对标准关键字inline的补充。为什么要添加这个非标准关键字呢?先让我们来看看inline的一些局限,决定一个声明为inline的函数是否真的进行嵌入,完全取决于编译器的判断。因此inline只是一个建议,在一些情况下,比如在一些内嵌函数中包含有循环或是这个函数体太大了,那么即使这个函数声明为inline,编译器也将拒绝这个函数的嵌入。
与此相反,非标准关键字__forceinline 将忽略编译器的判断并强迫编译器去嵌入一个它本该拒绝嵌入的函数。我不太肯定使用这个关键字的意义,它可能会使可执行文件变得臃肿并降低cache的命中率。幸运的是,在一些极端条件下,编译器可能不接受__forceinline的任何请求。所以,一般情况下最好是使用标准的inline,inline是可移植的并且让编译器去做出“正确的选择”。
__forceinline 只应在下列条件全为真的情况下使用:inline不被编译器接受;你的代码不需要向其它平台进行移植;并且你能肯定嵌入这个函数会提高性能。
第三朵花:类成员指针
我常常听到很多有关类成员指针的问题:“我使用VC,为什么我不能使用一个类方法的指针呢?编译错误信息是:
Cannot convert parameter 2 from 'long (unsigned long)'to'long (__cdecl *)(unsigned long)'我该怎么办?”下面的代码是解决方法之一:
//in the header
class CKernel:
{
long (*lpFunc)(DWORD);
long OLESendTC( DWORD dwInfo );
}
//in the cpp File
BOOL CKernel::Init()
{
lpFunc = OLESendTC;
return TRUE;
}
所有的类方法都有一个隐藏参数,一个指向类对象的指针。C++使用这个指针来寻找此方法可能会使用的类中任何数据的位置。如果你尝试并使用一个标准的函数指针来调用一个类的方法,C++将不能传递这个隐藏参数并引起问题。
为了解决这个问题并改善类型安全,C++添加了三个新的操作符,::*,.*,与->*,它们既可指向成员函数也可指向成员变量。
class CTest
{
public:
BOOL Init();
long OLESendTC(DWORD dwInfo);
};
long (CTest::*lpFunc)(DWORD dwInfo) = &CTest::OLESendTC;
int main()
{
CTest test;
(test.*lpFunc)(0);
return 0;
}
long CTest::OLESendTC(DWORD dwInfo)
{
cout << "IN OLESENDTC\n";
return 0;
}
这个例子展示了这些运算符的一种用法。代码使用::*去声明lpFunc为类CTest成员函数的指针。注意最好在运行时给这个指针赋值,简单的方法是在声明时初始化它。在main函数中使用.*运行符来调用lpFunc所指向的方法。如果test在这是一个指针,你可以使用->*来代替。
C++有很多类似的隐藏特性,我们要在学习中对此多加注意。