NULL 和 0 的歧義
先看下NULL的定義,在stddef.h中(/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/stddef.h)
在C中,NULL定義爲((void*)0)。
在C代碼中,一般用NULL表示空指針,即指針的0值。例如:
int *p = NULL; // 正確
int *p = 0; // 正確
在C++中,NULL定義爲0或者0L。(是0還是0L跟編譯器定義的頭文件有關)
在C++98代碼中,我們也只能用NULL來表示空指針。例如:
#include <iostream>
using namespace std;
class Test
{
public:
void func()
{}
};
int main()
{
int *p = NULL; // NULL表示普通指針的0值,即空指針
int *p1 = 0; // 同上
void (Test::*p_func)() = NULL; // NULL表示指向成員函數的指針的0值,函數指針
void (Test::*p1_func)() = 0; // 同上
}
// compile cmd
// g++ -g -std=c++11 main.cpp -o main
到現在爲止,似乎一切看起來都還挺好的,沒什麼歧義啊。那我們現在考慮C++函數重載的一種情況,如下:
#include <iostream>
using namespace std;
class Test
{
public:
void func(int a)
{
cout << "call int.." << endl;
}
void func(bool b)
{
cout << "call bool.." << endl;
}
void func(void* c)
{
cout << "call void*.." << endl;
}
};
int main()
{
Test a;
a.func(0); // 調用func(int)
a.func(NULL); // 混亂,且編譯不通過
}
// compile cmd
// g++ -g -std=c++11 main.cpp -o main
按照我們編碼的意思,a.func(NULL)應該會調用func(void*)纔對,但是實際情況卻是編譯不通過,如下:
爲什麼呢?
1、a.func(0)這個沒問題,是因爲0被編譯器正確地、嚴格地認爲是int型,所以嚴格調用了func(int)。
2、但是NULL被認爲是0L,這時候沒有一個函數能嚴格匹配,所以0L就要被轉換,但是轉換成int、bool、void*都可以哪,所以編譯器就混亂了,不知道你到底想要調用哪個函數。
解決方案有三種:
case1:再定義一個func(long)函數,就可以使得NULL嚴格地和long匹配。
void func(long d)
{
cout << "call long.." << endl;
}
但是,這時候編譯還是有warning,如下:
case2:就是不要讓廣義整型數和指針重載(這是C++98一個好的編程習慣)。
case3:引入nullptr。