走进C++11(十一) nullptr/nullptr_t

C++ nullptr详解
本文详细介绍了C++11中引入的nullptr关键字,解释了它与NULL的区别,以及为何需要引入nullptr。通过示例展示了nullptr如何避免类型歧义,并强调了nullptr的类型特性。

 

解释

 

关键词 nullptr 代表指针字面量。它是 std::nullptr_t 类型的纯右值。存在从 nullptr 到任何指针类型及任何成员指针类型的隐式转换。同样的转换对于任何空指针常量也存在,空指针常量包括 std::nullptr_t 的值,以及宏 NULL。

 

引入原因

 

为什么引入nullptr呢, 不是有NULL这个关键字么?

 

的却,但是我想问你NULL是什么类型的?

 

C++98中NULL是个宏定义,明确规定NULL是个整型0值:

 

/* Define NULL pointer value */#ifndef NULL    #ifdef __cplusplus        #define NULL    0    #else  /* __cplusplus */        #define NULL    ((void *)0)    #endif  /* __cplusplus */#endif  /* NULL */

 

C中NULL规定为void*指针:

 

#define  NULL  ((void*)0)

 

可以看出,C和C++中NULL的规定是不同的,原因在于C++的重载机制。

 

void foo(int) {}void foo(int*) {}
foo(0);  // 调用foo(int)而不是foo(int*)foo(NULL);  // 如果NULL是0,则调用foo(int); 如果NULL是0L,则编译错误

 

C++98规定NULL是一个整型0值,根据不同的编译器实现,可能是0或0L。更尴尬的是,可以拿NULL当合法的整型(int或者long)来使用,所以C++11引入了nullptr表示指针的0值,虽然它不是指针类型,但是它能够转换成任何指针,而且它不能转换成int或者其他类型:

 

void foo(char *);void foo(int);#include <iostream>#include <typeinfo>int main(){  std::cout << "" << typeid(NULL).name() << std::endl;}foo(0); // 调用 foo(int)// foo(NULL); // 该行不能通过编译foo(nullptr); // 调用 foo(char*)

 

std::nullptr_t

 

nullptr也有其自身的类型,它的类型为std::nullptr_t。std::nullptr_t本身不是指针类型,但是它可以转换为任何指针类型,这也就是nullptr可以看做任何指针类型的原因。它的定义如下:

 

typedef decltype(nullptr) nullptr_t;

 

上面是一个很有趣的类型定义。通常情况是先有类型,然后才有该类型的变量。而上面的定义则是,先有一个某类型的字面值,再由这个字面值定义它的类型。妙哉!

 

关注公众号获取更多信息:

### 3.1 Qt头文件的结构与命名规则 在Qt中,标准类的头文件通常没有 `.h` 后缀。每个类对应一个头文件,且头文件名与类名一致。例如,`QApplication` 类的头文件名为 `QApplication`,而非 `QApplication.h`。这种命名方式简化了代码的可读性和一致性,使得开发者在引用类时可以直接使用类名作为头文件名[^1]。 ```cpp #include <QApplication> ``` 上述代码引入了 `QApplication` 类,该类用于管理图形用户界面应用程序的控制流和主要设置。它负责处理来自窗口系统和其它资源的事件,并提供对话管理功能。每个使用Qt的图形界面应用程序都必须包含一个 `QApplication` 对象,无论应用程序是否显示窗口[^1]。 ### 3.2 类的定义与事件循环 在一个典型的Qt程序中,除了 `QApplication` 之外,通常还会定义一个自定义的窗口类。例如,`MyWidget` 是一个继承自 `QWidget` 的类,用于创建主窗口界面。该类的声明通常位于独立的头文件中,如 `mywidget.h`。这种结构使得类之间的引用更加清晰,同时也便于代码维护[^3]。 ```cpp // mywidget.h #ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> class MyWidget : public QWidget { Q_OBJECT public: explicit MyWidget(QWidget *parent = nullptr); ~MyWidget(); }; #endif // MYWIDGET_H ``` 上述代码使用了条件编译指令 `#ifndef`、`#define` 和 `#endif`,以防止头文件被多次包含。这是C++中常见的做法,用于避免重复编译问题。`explicit` 关键字用于防止构造函数被隐式调用,确保对象的构造过程是显式的,从而减少潜在的错误[^2]。 ### 3.3 程序入口与事件循环启动 在Qt程序的主函数中,`QApplication` 对象的创建和销毁由 `main()` 函数负责。程序进入事件循环是通过调用 `exec()` 方法实现的,该方法会启动主事件循环,等待并处理用户输入和系统事件。在 `exec()` 中,Qt 接受并处理事件,并将其传递给相应的窗口部件。 ```cpp // main.cpp #include <QApplication> #include "mywidget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MyWidget w; w.show(); return a.exec(); } ``` 在上述代码中,`QApplication` 对象 `a` 被创建,并传入命令行参数。`MyWidget` 实例 `w` 被创建并调用 `show()` 方法显示窗口。最后,程序通过调用 `a.exec()` 进入事件循环,等待用户交互。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值