一、关于nullptr的面试题
下面的代码在什么情况下,没有问题。
int main() {MyClass* ptr = nullptr;ptr->Function1(); return 0;
}
通常来说,ptr是一个空指针,用空指针来调用函数是不可能的,怎么肯能正确呢?
二、回顾一下nullptr的基础知识
nullptr
是 C++11 引入的一个关键字,用于表示空指针,它解决了 C++ 此前在空指针表示方面存在的一些问题,以下是关于它的基础知识介绍:
- 引入背景
- 在 C++98 标准中,空指针通常用宏
NULL
来表示,而NULL
被定义为((void*)0)
,本质上是一个值为0的整数常量。这种定义方式在函数重载场景下容易引发歧义。例如,当一个函数接受int
指针参数,另一个函数接受int
类型参数时,传入NULL
可能导致编译器调用错误的函数,因为NULL
既能被当作指针类型,也能被当作整型。 - 为了消除这类二义性,C++11 引入了
nullptr
。
- 在 C++98 标准中,空指针通常用宏
- 类型
nullptr
的类型是std::nullptr_t
,这是一种独特的类型,它可以隐式转换为任何指针类型,但不能转换为非指针类型,如整数类型。这就保证了类型安全,避免像过去使用NULL
时可能出现的混淆。例如:
void foo(int*);
void foo(int);int main() {foo(nullptr); // 正确调用foo(int*)// foo(NULL); // 在旧代码中,这会有歧义,可能导致错误调用return 0;
}
- 用法
- 用于初始化指针变量,明确地将指针设置为空状态。例如:
int* p = nullptr;
class MyClass;
MyClass* objPtr = nullptr;
- 作为函数参数传递,当函数期望接收一个指针参数,并且当前没有有效的指针可传时,使用 `nullptr` 清晰表明“这里没有指向有效对象的指针”:
#include <iostream>
#include <memory>void printMessage(const char* msg) {if (msg!= nullptr) {std::cout << msg << std::endl;} else {std::cout << "No message." << std::endl;}
}int main() {printMessage(nullptr);return 0;
}
- 与
0
和NULL
的区别0
是一个整型常量,虽然在很多情况下能当作空指针使用,但编译器只是做了隐式转换,这种隐式转换正是造成类型混淆的根源。NULL
本质上等同于0
,同样有潜在风险。而nullptr
从类型上就杜绝了与整型混淆的可能性,使代码语义更加清晰,编译时也能更精准地处理指针相关逻辑。
三、如何保证面试题能够不出问题
从上面的基础知识回顾中,可以发现,nullptr不同于0和NULL,它实际上是一个类型。如果在运行时,用该指针调用,应该是会报错的,但是如果是在编译时,就有效。考虑下面的代码:
class MyClass {
public:static void Function1() {std::cout << "This is a static function." << std::endl;}
};
int main() {MyClass* ptr = nullptr;ptr->Function1(); return 0;
}
在上述示例中,虽然ptr
是nullptr
,但由于静态函数不依赖于对象的实例,而是属于类本身,所以可以通过nullptr
转换后的指针来调用静态函数。实际上,在这种情况下,即使指针为nullptr
,编译器在解析函数调用时,会直接根据指针的类型找到对应的类和静态函数进行调用,而不会对指针进行解引用操作,因此不会出现空指针解引用的错误。