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关键字,禁止隐式类型转换。

目录
相关文章
|
6月前
|
存储 C++
C/C++中位操作符(&,|,^,~)的详解使用
C/C++中位操作符(&,|,^,~)的详解使用
|
6月前
|
安全 编译器 程序员
【C++ 修饰符关键字 explicit 】掌握C++中的explicit :构造函数行为和初始化综合指南
【C++ 修饰符关键字 explicit 】掌握C++中的explicit :构造函数行为和初始化综合指南
428 3
|
5月前
|
C++
|
3月前
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
43 0
|
6月前
|
编译器 C语言 C++
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象(上)
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象
45 1
|
6月前
|
编译器 C++
【C++】类与对象(static、explicit、友元、隐式类型转换、内部类、匿名对象)
【C++】类与对象(static、explicit、友元、隐式类型转换、内部类、匿名对象)
33 2
|
6月前
|
Java 编译器 C语言
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象(下)
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象
31 0
|
6月前
|
C语言 C++
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象(中)
从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象
45 0
|
6月前
|
算法 安全 程序员
【C++14 新特性 透明操作符】透视C++14透明操作符Functors:深入理解与实践
【C++14 新特性 透明操作符】透视C++14透明操作符Functors:深入理解与实践
160 3
|
6月前
|
算法 程序员 C语言
【C++ 运算符重载】深入理解C++迭代器中的前置与后置++操作符
【C++ 运算符重载】深入理解C++迭代器中的前置与后置++操作符
245 0