C++ 隐式的类类型转换

转换构造函数

  如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,有时我们把这种构造函数称作为转换构造函数

实例
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

class Animal
{
public:
    Animal(string name):m_name(name) {}

    // 比较动物的名字
    bool isSame(Animal animal)
    {
        return m_name == animal.m_name;
    }

private:
    string m_name;
};

int main()
{
    Animal dog("dog");
    // 打印为 1
    cout << dog.isSame(string("dog")) << endl; 
    getchar();
    return 0;
}

  在示例中定义接受 string 的构造函数就是定义了从 string 类型向Animal隐式转换的规则。编译器用给定的 string 参数自动创建了一个 Animal对象,新生成的这个临时 Animal 对象被传递给 isSame,然后进行比较。

只允许一步类类型转换

  编译器只会自动地执行一步类型转换。如果我们把上例中的dog.isSame(string(“dog”)) 换成 dog.isSame(“dog”), 那么编译器就会报错:

不存在从 “const char [4]” 转换到 “Animal” 的适当构造函数”,因为它经历了两步转换。

  1. 从 “dog”转换成 string
  2. 从 string转换成Animal

因此我们可以这样做:

// 显示地转换成 string,隐式地转换成 Animal
dog.isSame(string("dog"));
// 或者
// 隐式地转换成 string, 显示地转换成 Animal
dog.isSame(Animal("dog"));

隐式转换的副作用

  有时隐式转换会带来很大的副作用,比如,标准库中的 vector 的接受一个容量参数的构造函数是禁止隐式转换的,如果不禁止,那么

std::vector a(5)

可声明一个初始长度为5的vector,但是这样写

std::vector a=5

就也是可以的了。极大地降低了可读性。

禁止隐式转换

  我们可以将构造函数声明为 explicit 来禁止隐式转换。而且 explicit 构造函数只能用于直接初始化即当我们执行拷贝形式的初始化时(使用=)时不允许的。
如果我们不加 explicit:

Animal dog("dog"); // 正确 
Animal cat = "cat"; // 正确 发生隐式类类型转换 
dog.isSame(string("dog")); // 正确 发生隐式类类型转换

如果我们加上 explicit:

Animal dog("dog"); // 正确
Animal cat = "cat"; // 错误 不允许隐式类类型转换
dog.isSame(string("dog")); // 错误 不允许隐式类类型转换

// 可以显示的进行类类型转换
Animal cat = Animal("cat"); // 正确
dog.isSame(Animal("dog")); // 正确

  所以标准库中的 vector 的接受一个容量参数的构造函数是禁止隐式转换的,声明了构造函数为 explicit。
  关键字 explicit 只对一个实参的构造函数有效。需要多个实参的构造函数不能用于隐式转换,所以无须将这些构造函数指定为 explicit 的。只能在类内声明构造函数时使用 explicit 关键字,在类外部定义时不应重复。

参考 《C++ primer》第五版

猜你喜欢

转载自blog.csdn.net/a844651990/article/details/79229162