一 具体实现 代码(c++)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const class nullptr_t { public : template <class T > inline operator T *() const { return 0 ; } template <class C , class T > inline operator T C : :*() const { return 0 ; } private : void operator &() const ; } nullptr = {};
来自维基百科 #####二 解析
在vs2013写了如下代码,作为解析演示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 //nullptr.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using namespace std; const class mynullptr_t { public: template<class T> inline operator T*() const { cout << "T* is called" << endl; return 0; } template<class C, class T> inline operator T C::*() const { cout << "T C::* is called" << endl; return 0; } private: void operator&() const; } mynullptr = {}; class A{ public: int *a; }; int main(){ int *p = mynullptr; int A::*a = mynullptr; cout << p << endl; cout << a << endl; }
结果输出
1 2 3 4 T* is called T C::* is called 00000000 0
2.解释 首先申明了一个类(为了避免冲突我使用了mynullptr_t)使用了const修饰,意味着里面的变量是不能更改的。 同时类里面有两个公有函数如下:
1 2 3 4 template<class T> operator T*() const; template<class C, class T> operator T C::*() const
其中template表示模板,意味着,T可以使用户自定义的类型。既然是空指针,那么很多种类型的指针都可以指向它,所以使用了模板。使用了operator关键字,operator表示重载,重载有很多种,在这里此函数为一个隐式转换函数。const表示此函数不修改类的成员变量。如果对这方面不是很清楚可以参考 1.c++模板详解 2.C++ operator两种用法 这两篇博客。
在函数里面只做了一件事也就是返回0,为什么返回0呢?因为在对指针赋值时如果指针=0,也即意味着这个指针为一个空指针。原因是因为在<stdio.h>头文件下有以下定义:
1 2 3 4 5 6 7 8 /* Define NULL pointer value */ #ifndef NULL #ifdef __cplusplus #define NULL 0 #else /* __cplusplus */ #define NULL ((void *)0) #endif /* __cplusplus */ #endif /* NULL */
将NULL 定义为了0; 不信的话可以试一试
1 2 int *p = 0; cout << p << endl;
输出:00000000
第二个函数和上面的一样只是模板不同
1 2 3 4 5 6 template<class C, class T> operator T C::*() const { cout << "C::T* is called" << endl; return 0; }
目的是为了给类的成员指针 变量赋予空指针。所以你可以根据你自己的需求写出各种模板参数。
private中void operator&() const;
即为将&符号禁用。因为空指针没有引用这一说。
3.检验测试 在main函数中分别定义了一下变量
1 2 int *p = mynullptr; int A::*c = mynullptr;
int *
的指针p并赋予空指针,和以及对类A 的成员指针赋予空指针。 要把mynullptr赋给左边的值,由于右边mynullptr的类型与左边不同,所以此时要进行隐式类型转化,如何转化呢?还记得我们在类中写的那两个函数吗,他们就是隐式转化的函数。根据左边的类型去匹配模板,第一个当然与T*
匹配,所以调用第一个隐式转化函数,于是结果打印了T*is called
同样的第二个应该调用第二个隐式转换函数,打印了C::T* is called
。我们知道空指针的地址为0地址,所以第一个打印了00000000(32位系统指针占4个字节,所以是8个0)。第二个由于是成员指针,代表的是偏移量,所以打印了0。