C++11之显式转换操作符-explicit

简介: C++11之显式转换操作符-explicit

隐式类型转换

在C++中存在着一把双刃剑—隐式类型转型。好处是可以编写过多的构造函数,坏处是总会有一些意外情况并非程序员所愿。


场景1

下面分别实现了有无被explicit关键字修饰的类和函数。

#include <iostream>
using std::cout;
using std::endl;
class Rational1
{
public:
  Rational1(int n = 0, int d = 1):num(n), den(d)
  {
    cout << __func__ << "(" << num << "/" << den << ")" << endl;
  }
public:
  int num; // 被除数
  int den; // 除数
};
class Rational2
{
public:
  explicit Rational2(int n = 0, int d = 1) :num(n), den(d)
  {
    cout << __func__ << "(" << num << "/" << den << ")" << endl;
  }
public:
  int num; // 被除数
  int den; // 除数
};
void Display1(Rational1 r)
{
  cout << __func__ << endl;
}
void Display2(Rational2 r)
{
  cout << __func__ << endl;
}
int main()
{
  Rational1 r1 = 11;
  Rational1 r2(11);
  Rational2 r3 = 11; // error E0415
  Rational2 r4(11);
  Display1(1);
  Display2(2); // error  E0415
  return 0;
}


运行报错:这是因为Rationl2这个类没有对应int参数的构造函数。

在这里,并没有体现出explicit的优点,甚至觉得有它使得代码更加麻烦。但是我们必须要阻止那种带有歧义的隐式类型转换。


场景2

这里的例子来自C++11提案,但有一些细微的变动。定义了一个Ptr类,并实现了bool类型转换。这样我们就可以很方便使用if(p)来判断指针是否有效。但是带来的坏处就是支持Ptr对象的相加运算,例如 p + pd

#include <iostream>
using std::cout;
using std::endl;
template<class T>
class Ptr
{
public:
  Ptr(T* p) :m_p(p) {}
  operator bool() const
  {
    return m_p != nullptr ? true : false;
  }
private:
  T* m_p;
};
int main()
{
  int a = 11;
  Ptr<int> p(&a);
  if(p)
  {
    cout << "valid pointer." << endl; // 有效的指针
  }
  else
  {
    cout << "invalid pointer." << endl; // 无效的指针
  }
  Ptr<int> pd(0);
  cout << p + pd << endl; 
  cout << pd << endl;
  return 0;
}


运行结果:

valid pointer.
1
0


很明显这并不是我们想要的结果。这时我们只需要使用explicit关键字修饰到bool类型转换上就可以有效的防止这种”意外“发生。

在bool运算符重载中添加explicit

运行结果:

没有找到接受’Ptr(int>'类型左操作数的操作符(或者没有可接受的转换)。

场景3

这里定义了一个ConvertTo和Convertable类。在Convertable类中有一个显式转换到ConverTo类的方法。

#include <iostream>
using std::cout;
using std::endl;
class ConvertTo{};
class Convertabkle
{
public:
  explicit operator ConvertTo() const
  {
    return ConvertTo();
  }
};
void Func(ConvertTo ct)
{
}
int main()
{
  Convertabkle c;
  ConvertTo ct(c); 
  ConvertTo ct2 = c;  // 拷贝构造函数  error
  ConvertTo ct3 = static_cast<ConvertTo>(c);  // C++11的强制类型转换
  Func(c); // 拷贝构造函数 error
  return 0;
}


那么这样就会使得只有直接初始化或者使用强制类型转换才可以进行转换,不能再通过拷贝构造函数隐式转换了。

总结

1、从上面几个例子中,可以看出显示类型转换explicit关键字并没有完全禁止从源类型到目标类型的转换,只是不允许拷贝构造函数和隐式类型转换罢了。所以我们就不能通过复制发方式或者通过函数参数的形式进行从源类型到目标类型的转换。

2、所以我们有必要在创建类时及时添加explicit关键字,禁止隐式类型转换。

目录
相关文章
|
2月前
|
存储 C++
C/C++中位操作符(&,|,^,~)的详解使用
C/C++中位操作符(&,|,^,~)的详解使用
|
2月前
|
安全 编译器 程序员
【C++ 修饰符关键字 explicit 】掌握C++中的explicit :构造函数行为和初始化综合指南
【C++ 修饰符关键字 explicit 】掌握C++中的explicit :构造函数行为和初始化综合指南
113 3
|
2月前
|
算法 程序员 C语言
【C++ 运算符重载】深入理解C++迭代器中的前置与后置++操作符
【C++ 运算符重载】深入理解C++迭代器中的前置与后置++操作符
44 0
|
2月前
|
设计模式 存储 算法
【C++ 函数调用操作符】探究C++中的函数调用操作符 基础到高级应用
【C++ 函数调用操作符】探究C++中的函数调用操作符 基础到高级应用
277 0
|
2月前
|
算法 安全 程序员
【C++14 新特性 透明操作符】透视C++14透明操作符Functors:深入理解与实践
【C++14 新特性 透明操作符】透视C++14透明操作符Functors:深入理解与实践
41 3
|
2月前
|
存储 程序员 C++
C/C++ 内存分配 new 操作符:剖析new操作符的实现机制和使用技巧
C/C++ 内存分配 new 操作符:剖析new操作符的实现机制和使用技巧
26 0
|
4月前
|
C++
C++——类和对象(初始化列表、匿名对象、static成员、类的隐式类型转换和explicit关键字、内部类)
C++——类和对象(初始化列表、匿名对象、static成员、类的隐式类型转换和explicit关键字、内部类)
|
4月前
|
C++
C++ operator关键字的使用(重载运算符、仿函数、类型转换操作符)
C++ operator关键字的使用(重载运算符、仿函数、类型转换操作符)
31 0
|
4月前
|
算法 编译器 C++
【C++11保姆级教程】深入浅出异常说明符、异常操作符和lambda表达式
【C++11保姆级教程】深入浅出异常说明符、异常操作符和lambda表达式
|
5月前
|
编译器 C++
[C++ 从入门到精通] 8.构造函数详解、explicit、初始化列表
[C++ 从入门到精通] 8.构造函数详解、explicit、初始化列表
40 0