Cherno C++学习笔记 P40 隐式转换与explicit关键字

发布于:2024-12-18 ⋅ 阅读:(36) ⋅ 点赞:(0)

这一篇文章会讲一下有关于C++的隐式转换问题,主要是涉及到类的初始化。

C++当中的隐式转换,指的是不需要告诉编译器我们真正想要的是什么,它就会像有一点自动的样子一样执行一些格式转换功能。通常C++的编译器允许我们进行一次隐式转换,当我们把一种type的数据当成另一种type用的时候,我们不需要进行casting这种强制转换。

在这里我们还是用经典的entity类举一个例子,我们在Entity类当中定义两个成员变量,分别是name和age,然后我们定义两个构造函数分别用来接收一个输入进行初始化:

class Entity {
private:
	std::string m_Name;
	int m_Age;
public:
	Entity(const std::string&name)
		:m_Name(name), m_Age(-1){}
	Entity(const int& age)
		:m_Name("Unknown"), m_Age(age){}
};

那么如果我们想要初始化这个类的实例,我们应该怎么做?首先我们可以用最常规的方法:

Entity e1("Cherno");
Entity e2(22);

但是在有隐式转换的情况下,我们还可以剑走偏锋,搞点花活,如下所示:

Entity e1 = (std::string)"Cherno";
Entity e2 = 22;

这样看起来会感觉有点神奇,为什么我们可以直接让Entity变量等于一个string或者一个int?因为我们的构造函数写法的原因,编译器会自动进行一次隐式类型转换,把string/int类型转变成了我们需要的Entity类型,所以我们这样直接写赋值才会通过。

虽然但是,这里有一个和Cherno视频内容完全不同的部分!在Cherno视频当中,像下面这样写是合法的,但是在我使用的VS2022当中,这样写就已经不正确了:

Entity e1 = "Cherno";

因为我们的字面量其实是一个const char[]类型,那么它转换到string是一次类型转换,而string到Entity又是一次类型转换,这样就会连续发生两次转换,但是我们知道,编译器只接受一次隐式转换,所以我们需要手动进行一次强制类型转换,把const char[]转换为string。

同理,如果我们写一个以Entity引用为形参的函数如下所示:

void Function(const Entity& e) {
	std::cout << "Hello" << std::endl;
}

那么这个函数也同样会接受int/string作为实参输入:

Function(22);
Function((std::string)"Cherno");

实际上我觉得这个地方VS2022相当于是修了一个隐式转换的bug,因为如果我们看Cherno原视频,会发现在用const char[]为Entity赋值的时候没有问题,但是调用函数的时候就有问题了,这个地方其实解释不通的,因为都相当于做了两次隐式转换,为什么一个有问题一个没问题?这不合理好吧,不过还好现在VS2022已经没有这个bug了。

我们通过这样的隐式转换,可以大大简化代码,这个是一个有点,但是也带来了问题,就是代码看起来并不是很清晰,会感觉乱七八糟的,所以通常我们还是要用常规的初始化对象的办法,反正也没有什么损失对吧。

那么如果我们不想要隐式转换的话应该怎么办?答案是explicit关键字。我们将explicit关键字放在构造函数前面,会禁用该构造函数的隐式转换功能。

explicit Entity(const std::string&name)
	:m_Name(name), m_Age(-1){}

如下所示,那么我们所有使用该构造函数的隐式转换都会被禁用,也意味着这个构造函数必须要被显式调用。这样可以防止意外地类型转换,保证我们的代码安全。


网站公告

今日签到

点亮在社区的每一天
去签到