看到同事用了一下nullptr.不是很了解这方面东东,找个帖子学习学习 http://www.cppblog.com/airtrack/archive/2012/09/16/190828.aspx

NULL:

NULL是c语言的东西,定义处: #define NULL ((void *)0)

我们可以写  int* i = NULL, foo_t* pObj = NULL.

NULL实际上是一个void *的指针,然后吧void *指针赋值给int *和foo_t *的时候,会隐式转换成相应的类型。而如果换做一个C++编译器来编译的话是要出错的,因为C++是强类型的,void *是不能隐式转换成其他指针类型的,所以通常情况下,编译器提供的头文件会这样定义NULL:

#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif

C++ 的0

因为C++中不能将void *类型的指针隐式转换成其他指针类型,而又为了解决空指针的问题,所以C++中引入0来表示空指针,这样就有了类似上面的代码来定义NULL。实际上C++的书都会推荐说C++中更习惯使用0来表示空指针而不是NULL,尽管NULL在C++编译器下就是0。为什么C++的书都推荐使用0而不是NULL来表示空指针呢?我们看一个例子:

 //foo.h
void bar(type1 a, type2* b); //foo.h中的bar函数在a.cpp和b.cpp中都被调用了. //a.cpp
.....
bar(a,b);
..... //b.cpp
.....
bar(a, );
..... //现在,上面的代码都能编译运行.但是突然某天我们要功能扩展,需要对bar函数扩展,我们使用了重载 foo.h变成如下:
void bar(sometype1 a, sometype2 *b);
void bar(sometype1 a, int i); //这个时候就危险了.因为a.cpp和b.cpp中的调用代码这个时候就不能按照期望的运行了。但是我们很快就会发现b.cpp中的0是整数,也就是在overload resolution的时候,我们知道它调用的是void bar(sometype1 a, int i)这个重载函数,于是我们可以做出如下修改让代码按照期望运行: bar(a, static_cast<type2 *>()); //我知道,如果我们一开始就有bar的这两个重载函数的话,我们会在一开始就想办法避免这个问题(不使用重载)或者我们写出正确的调用代码,然而后面的这个重载函数或许是我们几个月或者很长一段时间后加上的话,那我们出错的可能性就会加大了不少。貌似我们现在说道的这些跟C++通常使用0来表示空指针没什么关系,好吧,假设我们的调用代码是这样的:
//foo.h
void bar(type1 a, type2 *b); //a.cpp
......
bar(a, b);
......
//b.cpp
.....
bar(a,NULL);
..... //当bar的重载函数在后面加上来了之后,我们会发现出错了,但是出错的时候,我们找到b.cpp中的调用代码也很快可能忽略过去了,因为我们用的是NULL空指针啊,应该是调用的void bar(type1 a, type2 *b)这个重载函数啊。实际上NULL在C++中就是0,写NULL这个反而会让你没那么警觉,因为NULL不够“明显”,而这里如果是使用0来表示空指针,那就会够“明显”,因为0是空指针,它更是一个整形常量。 在C++中,使用0来做为空指针会比使用NULL来做空指针会让你更加警觉。

C++ 11的nullptr

 //虽然上面我们说明了0比NULL可以让我们更加警觉,但是我们并没有避免这个问题。这个时候C++ 11的nullptr就很好的解决了这个问题,我们在C++ 11中使用nullptr来表示空指针,这样最早的代码是这样的

 //foo.h

 void bar(type1 a, type2* b);
-------------------------------------------
7 | //a.cpp | //b.cpp |
| .... | ....... |
| bar(a,b); | bar(a, nullptr);|
| ....... | ........ |
---------------------------------------------
在我们后来把bar的重载加上了之后,代码是这样: //foo.h
void bar(type1 a, type2 *b);
void bar(type1 a, int i); //a.cpp //b.cpp
.... .....
bar(a,b); bar(a,nullptr);
.... ...... //这时候,我们的代码还是能够如期的正确运行. //在没有C++11的nullptr的时候,我们应该怎么解决避免这个问题呢?我们可以自己实现一个nullptr const
class nullptr_t
{
public:
template<class T>
inline operator T*() const
{ return ; } template<class C, class T>
inline operator T C::*() const
{ return ; } private:
void operator&() const;
} nullptr = {};


和小伙伴都惊了个呆了啊...上面自己实现的nullptr_t类完全看不懂的样子,得一句一句的分析分析啊...

 const                       //参见下文解释1
class nullptr_t
{
public:
template<class T>
inline operator T* () const //参见下文解释2
{
return ;
} template<class C, class T>
inline operator T C::*() const //参见下文解释3
{
return ;
} private:
void operator& () const; //参见下文解释4 }nullptr = {}; //参见下文解释5

解释1 : 在类前面的const是什么!!

 //类前面的const 是修饰 类后面定义的对象的.

 const
class A
{
public:
int i;
}a,b; //等价于
class A
{
public:
int i;
}; const A a;
const A b;

解释2 : 这个模板函数是什么?

 template <class T>
inline operator T* () const
{
return ;
} //上面的模板函数是在重载 类型转换运算符 (跟 重载 operator = 一样都是在重载运算符).
//我们知道重载运算符是要带返回值的,例如下面的类重载等号 是要返回A&的
class A
{
public:
A& operater = (const A& Obj)
{
i = Obj.i;
j = Obj.j;
}
private:
int i;
int j;
};
//但是呢.重载 类型转换运算符比较特殊. (c++ primer,可以查“用户自定义类型转换符”找到讲解) 规定为:转换函数不能写返回类型(规定的),返回的类型就是 operator 后面跟的类型
所以:
inline operator T* () const
---------------------------------------------
这是一个类型转换函数,把A类型(这里是return 0 的 0的类型)转换成 T*的类型
inline 表示内联函数,写不写无所谓。
operator 代表重载某种操作 operator T* () 就是重载类型转换
const 表示 成员变量是只读,不能改。 return _data; // 有返回值,返回值类型是operator后面的T*类型。

解释3 : 这个模板函数又是什么???

解释4:  只写函数声明,不写函数实现真的可以么??

事实证明是可以的,只有没人调用这个函数是可以编译运行成功的..但是如果有人调用的话编译就会报错了.

解释5: 类对象 = {} 中的 ={}是什么??

= {} 是c++11的语法,代表给这个变量初始化

聊一聊c++中指针为空的三种写法 ----->NULL, 0, nullptr的更多相关文章

  1. Android平台中实现对XML的三种解析方式

    本文介绍在Android平台中实现对XML的三种解析方式. XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能. 在 ...

  2. Java中获取键盘输入值的三种方法

    Java中获取键盘输入值的三种方法     Java程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值 ...

  3. MVC3中,在control里面三种Html代码输出形式

    MVC3中,在control里面三种Html代码输出形式:ViewData["msg"] = "<br /> Title <br />" ...

  4. jquery 在页面中三种写法

    jQuery 分 2 个系列版本 1.x 与 2.x,主要的区别在于 2.x 不再兼容 IE6.7.8浏览器,这样做的目的是为了兼容移动端开发.由于减少了一些代码,使得该版本比 jQuery 1.x ...

  5. Shell脚本中字符串判空:使用-z 字符串长度为0时,为真,-n字符串长度不为0,为真。这两个都不靠谱【转】

    最近发现使用  -z   和  -n  来判断字符串判空,或不空时,很不靠谱. 使用下面的方法最可靠: if [ "x${value}" == "x" ]    ...

  6. 在Tomcat中部署web项目的三种方式

    搬瓦工搭建SS教程 SSR免费节点:http://www.xiaokeli.me 在这里介绍在Tomcat中部署web项目的三种方式: 1.部署解包的webapp目录 2.打包的war文件 3.Man ...

  7. 【转载】取得系统中网卡MAC地址的三种方法

    From:http://blog.csdn.net/zhangting1987/article/details/2732135 网卡地址这个概念有点混淆不清.因为实际上有两个地址,mac地址和物理地址 ...

  8. Tomcat中部署web应用的三种方式

    Tomcat中部署web应用的三种方式(静态部署)       第一种,针对war或解压后的war,最为常用的是直接操作webapp目录,将完整的war包或者web应用直接放到webapp目录下.使用 ...

  9. spring中创建bean对象的三种方式以及作用范围

    时间:2020/02/02 一.在spring的xml配置文件中创建bean对象的三种方式: 1.使用默认构造函数创建.在spring的配置文件中使用bean标签,配以id和class属性之后,且没有 ...

随机推荐

  1. Android Studio 环境配置优化

    一.插件 .ignore: 版本控制忽略文件高亮和补齐ADB Idea: ctrl + Shift + A 查找中添加常用卸载安装app的一些操作,无需命令行Android ButterKnife Z ...

  2. xml基础小结

    XML基础 1)XML的作用 1.1 作为软件配置文件 1.2 作为小型的“数据库” 2)XML语法(由w3c组织规定的) 标签: 标签名不能以数字开头,中间不能有空格,区分大小写.有且仅有一个根标签 ...

  3. GC overhead limit exceeded解决

    java.lang.OutOfMemoryError: GC overhead limit exceeded解决   一.异常如下:Exception in thread "main&quo ...

  4. JSTL 数字日期标签库

    <frm:formatNumber/>标签 该标签依据特定的区域将数字改变为不同的格式来显示. 被格式化的数据<frm:formatNumber> <fmt:format ...

  5. Cocos2d-x游戏中默认的AndroidManifest.xml的解析

    直接上代码说明: <?xml version="1.0" encoding="utf-8"? > <!-- xmlns:android=&qu ...

  6. 字符集详解 ------------------------ UNICODE +UTF8

    http://my.oschina.net/goldenshaw/blog?catalog=3294521 http://my.oschina.net/goldenshaw/blog?catalog= ...

  7. spring注解:@PostConstruct和@PreDestroy

    关于在spring  容器初始化 bean 和销毁前所做的操作定义方式有三种: 第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作 第二 ...

  8. pnd_start_2

    试过才知道一点都不简单,虽然表现出的逻辑是错的,但是至少运行上是正确的.

  9. CentOS7上GitLab的使用

    生成SSH Keys 生成root账号的ssh key # ssh-keygen -t rsa -C "admin@example.com" 显示pub key的值 # cat ~ ...

  10. nginx同时监听本机ipv4/ipv6端口

    修改nginx.conf配置文件 server { listen ; listen [::]:; } 0.0.0.0  表示本机所有ipv4地址,需要监听特定地址替换即可 [::]  表示本机所有ip ...