NULL 0 和 c ++ 11 nullptr
简单描述就是因为c语言有隐士类型转换所以(void*)可以转化为任意一种指针可是c++并不提供这种方式所以在一些赋值操作中要强转,为了兼容和使用上的一致就定义了
c++ NULL 是0 但是这个0又会产生和数字0的奇异性造成使用上的麻烦,所以产生了一个新的机制c++11提供的nullptr 具体定义如下图
template
_LIBCPP_ALWAYS_INLINE _LIBCPP_CONSTEXPR
operator _Tp* () const {return 0;}
_Tp 应该是一种类型,但是我从没有见到过这种使用方式,所以写一段代码实验一下。示例代码如下:
#include
using namespace std;
class Base
{
int mem;
public:
Base() : mem(0) {}
int operator*() { return 1; };
operator int*() { return 0; }
};
int main()
{
Base b;
std::cout << "*b: " << *b << std::endl;
std::cout << "b: " << b << std::endl;
return 0;
}
上面的输出结果如下:
$ g++ test.cpp
// ---------- ouput --------
$ *b: 1
$ b: 0
环境:ubuntu14.04 g++4.8.4
从上面的输出结果可以看到 *b 调用的是 "int operator*() { return 0; }",也就是运算符 * 的重载形式;而 b 调用的是 "operator int*() { return 0; }"。将该段代码的AST打印出来如下:
clang -Xclang -ast-dump test.cpp
// ---------AST---------
CXXConversionDecl 0xa745170 <line:13:2, line:16:2> line:13:2 used operator int * 'int *(void)'
| | `-CompoundStmt 0xa7452d8 <line:14:2, line:16:2>
| | `-ReturnStmt 0xa7452c8 <line:15:3, col:10>
| | `-ImplicitCastExpr 0xa7452b8 <col:10> 'int *' <NullToPointer>
查阅Clang源码,查找CXXConversionDecl的定义,注释如下:
/// \brief Represents a C++ conversion function within a class.
2454 ///
2455 /// For example:
2456 ///
2457 /// \code
2458 /// class X {
2459 /// public:
2460 /// operator bool();
2461 /// };
2462 /// \endcode
2463 class CXXConversionDecl : public CXXMethodDecl {
2464 void anchor() override;
2465 /// Whether this conversion function declaration is marked
2466 /// "explicit", meaning that it can only be applied when the user
2467 /// explicitly wrote a cast. This is a C++11 feature.
/// ...
}
从上面的代码中看到 operator int*() {} 是一种类型转换运算符重载(type-cast operator)形式,将类型 Base 的对象转换为 int* 类型。可是刚开始我为什么没有看出来这是一种类型转换运算符重载呢?
估计是由于在日常编码过程中我见到的大抵都是如下这种形式:
class MyInt
{
int num;
public:
MyInt(int num) : num(num) {}
// 这里的类型都很简单
operator int() { return num; }
};
但是在这个示例中出现了复合类型(compound type - (that is, array, function, object pointer, function pointer, member object pointer, member function pointer, reference, class, union, or enumeration, including any cv-qualified variants),所以有些违背直觉。其实类型转换运算的目的类型也可以很复杂,例如 operator const int*&() 等等。
另外这里的问题不仅仅在于类型转换的目的类型比较复杂,还在于类型转换运算符(type-cast operator)本身就比较特殊,"The type-cast operator uses a particular syntax: it uses the operator keyword followed by the destination type and an empty set of parentheses." ,使用了operator运算符,但是不像 + 或者 *,会出现在函数声明中,例如
> int operator*() { return 0; }
如果类型运算符重载使用下面这种形式的话,估计更易读一些。
> int* operator type_cast() { return 0; }
可惜,类型转换运算符的重载偷了个懒,直接将前面的 int* 挪到了后面,成了 operator int*() {} ,所以就带来了些困扰。
对于自定义类型来说,大致有三种隐式类型转换的方式。
注:上述描述来自Type conversions,下面的示例代码也恬不知耻的抄袭了此处
// implicit conversion of classes:
#include
using namespace std;
class A {};
class B {
public:
// conversion from A (constructor):
B (const A& x) {}
// conversion from A (assignment):
B& operator= (const A& x) {return *this;}
// conversion to A (type-cast operator)
operator A() {return A();}
};
int main ()
{
A foo;
B bar = foo; // calls constructor
bar = foo; // calls assignment
foo = bar; // calls type-cast operator
return 0;
}
三种方式都可以在大部分场景下正常使用,但还是推荐在第一种和第三种前面加上 explicit 关键字,这样就要求程序员显示使用static_cast<>来进行类型的转换,方便阅读,例如"explicit operator A() { return A(); }"。
注:类型转换运算符是有返回值的,返回类型由 operator 后面的目的类型标明。
https://zhuanlan.zhihu.com/p/22502093 转载来自