C语言中NULL定义为(void*)0,它可以隐式转化为各种指针类型然后赋值,但C++中作为一门强类型语言自然是不允许void*类型向其它指针类型的隐式转化,于是修改了null的定义,在C++中null变为了字面量0
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
C++中null的重定义造成了一系列尴尬的问题,比如下面的代码
void fun(char*){}
void fun(int){}
void fun(long long){}
void fun(double){}
int main(){
fun(NULL);//编译出错,不知道调用哪个函数了
}
对此C++11引入了nullptr字面量,nullptr的类型是nullptr_t,它的定义是使用类型推导完成的。
namespace std{
using nullptr_t=decltype(nullptr);
....
}
由于nullptr是关键字,它的实现会由编译器完成所以很难找到实现的具体代码,数学老师教过我们对这类问题要大胆的猜测小心的验证,对此我使用模板模拟了一个nullptr(瑕疵在于类的大小不一致,健壮性有待提高)
class null {
public:
template<class Base>
constexpr operator Base* ()noexcept {
return static_cast<Base*>(0);
}
template<class T,class B>//支持成员指针
constexpr operator B T::* ()noexcept {
return 0;
}
};
#define nullptr_ static_cast<null&&>(null())
nullptr特点
- 可以为各种指针类型赋值
- 值在编译阶段确认,可以作为静态表达式
- 作为泛型指针类型不会隐式转化为别的类型或为别的类型的数据赋值
注意:nullptr是常量表达式,这并不是强调它是一个常量而是强调它的值在编译阶段确认,因此nullptr可以和static_assert一起使用实现禁止访问空地址的静态断言