众所周知,C语言使用NULL常量来表示空指针,为何C++11还要增长新的nullptr来表示空指针呢?函数
1,咱们首先查看NULL的定义:指针
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and <stddef.h> or need NULL. */
#undef __need_NULL
从上面的定义能够看出,若是定义了__GNUG__,编译器NULL其实就是__null,__null是编译器相关的行为(要么是常量0,要么是 (void *)0),有待进一步研究确认。编译器
所以,在C语言中,以下定义都是合法的:it
int a = NULL;
char b = NULL;
int *ptr = NULL;
io
2,在C++中,考虑以下重载示例:编译
void overloaded(int value) {
std::cout << "int value" << std::endl;
}语言
void overloaded(int *ptr) {
std::cout << "int *ptr" << std::endl;
}类型转换
int main() {
overloaded(NULL); // 歧义,由于NULL既能够是常量0,也能够是 void*指针。di
return 0;
}
因为C++支持函数重载,此时NULL的定义就会带来歧义,当咱们调用overloaded(NULL);的时候,编译器没法确认,究竟是把NULL做为常量0仍是做为 (void *)0,所以编译没法经过。co
为了解决这个问题,C++11引入了nullptr常量,该常量是std::nullptr_t类型。std::nullptr_t类型能够转换为任意指针类型(相似于void *,也能够转换为任意指针类型),同时也能够转换为bool类型(用以支持条件判断 !ptr),可是不能转换成整型类型。这样便消除了上面的重载歧义。
overloaded(nullptr); // ok,调用void overloaded(int *ptr);版本
转换成bool类型示例以下:
int main() {
std::nullptr_t ptr = nullptr;
if (!ptr) { // std::nullptr_t类型转换成bool类型
std::cout << "nullptr" << std::endl;
}
return 0;
}
3,固然,nullptr只是解决了整型和指针类型的重载问题,对于两个不一样指针类型的重载函数,nullptr没法区分出来:
void overloaded(int *ptr) {
std::cout << "int *ptr" << std::endl;
}
void overloaded(char *ptr) {
std::cout << "char *ptr" << std::endl;
}
int main() {
overloaded(nullptr); // 歧义,依然没法区分 int *和 char *
return 0;
}
这时候,可使用std::nullptr_t类型,以下:
void overloaded(int *ptr) {
std::cout << "int *ptr" << std::endl;
}
void overloaded(char *ptr) {
std::cout << "char *ptr" << std::endl;
}
void overloaded(std::nullptr_t ptr) {
std::cout << "std::nullptr_t ptr" << std::endl;
}
int main() {
overloaded(nullptr); // ok,输出 std::nullptr_t ptr
return 0; }