构造函数显式关键字的使用
usage of explicit keyword for constructors
我试图了解显式关键字在 c++ 中的用法,并在 SO 上查看了这个问题显式关键字在C++中是什么意思?
但是,那里列出的示例(实际上是前两个答案(对用法不是很清楚。例如
// classes example
#include <iostream>
using namespace std;
class String {
public:
explicit String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
String::String(int n)
{
cout<<"Entered int section";
}
String::String(const char *p)
{
cout<<"Entered char section";
}
int main () {
String mystring('x');
return 0;
}
现在我已经将 String 构造函数声明为显式,但是假设如果我不将其列为显式,如果我调用构造函数作为,
String mystring('x');
或
String mystring = 'x';
在这两种情况下,我都会进入 int 部分。除非我指定值的类型,否则它默认为 int。即使我对参数更具体,例如将一个声明为 int,另一个声明为 double,并且不使用显式构造函数名称并以这种方式调用它
String mystring(2.5);
或者这样
String mystring = 2.5;
它将始终默认为带有双精度作为参数的构造函数。所以,我很难理解显式的真正用法。你能给我一个例子,不使用显式将是一个真正的失败吗?
explicit
旨在防止隐式转换。任何时候您使用类似 String(foo);
的东西,这是一个显式转换,因此使用 explicit
不会改变它的成功或失败。
因此,让我们看一个确实涉及隐式转换的方案。让我们从您的String
课开始:
class String {
public:
explicit String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
然后让我们定义一个函数,它接收 String
类型的参数(也可以是 String const &
,但String
暂时可以(:
int f(String);
您的构造函数允许从char const *
进行隐式转换,但只允许从int
进行显式转换。这意味着如果我打电话:
f("this is a string");
。编译器将生成代码以从字符串文本构造 String 对象,然后使用该String
对象调用 f
。
但是,如果您尝试调用:
f(2);
它将失败,因为采用int
参数的 String
构造函数已标记为 explicit
。这意味着如果我想将int
转换为String
,我必须明确地执行此操作:
f(String(2));
如果String(char const *);
构造函数也被标记为 explicit
,那么你也无法调用f("this is a string")
- 你必须使用f(String("this is a string"));
但请注意,explicit
仅控制从某种类型foo
到您定义的类型的隐式转换。它对从某种其他类型的隐式转换为 explicit
构造函数采用的类型没有影响。因此,采用类型 int
的显式构造函数仍将采用浮点参数:
f(String(1.2))
。因为这涉及从double
到int
的隐式转换,然后是从int
到String
的显式转换。如果你想禁止从double
到String
的转换,你可以通过(例如(提供一个重载的构造函数来实现,该构造函数接受一个double
,但随后抛出:
String(double) { throw("Conversion from double not allowed"); }
现在,从double
到int
的隐式转换不会发生 - double
将直接传递给您的 ctor 而无需转换。
至于使用 explicit
可以实现什么:使用 explicit
的主要目的是防止编译本来可以编译的代码。当与重载结合使用时,隐式转换有时会导致一些相当奇怪的选择。
使用转换运算符而不是构造函数演示问题更容易(因为您只能使用一个类来演示(。例如,让我们考虑一个小字符串类,这些类与人们了解隐式转换的问题之前编写的许多类非常相似:
class Foo {
std::string data;
public:
Foo(char const *s) : data(s) { }
Foo operator+(Foo const &other) { return (data + other.data).c_str(); }
operator char const *() { return data.c_str(); }
};
(我通过使用std::string
来存储数据来作弊,但是如果我像他们一样存储char *
,并使用new
来分配内存,情况也是如此(。
现在,这使得这样的事情工作正常:
Foo a("a");
Foo b("b");
std::cout << a + b;
。而且,(当然(结果是它打印出ab
.但是,如果用户犯了一个小错误并键入-
他们打算键入+
的位置,会发生什么?
这就是事情变得丑陋的地方——代码仍然编译和"工作"(对于这个词的某些定义(,但打印出废话。在我的机器上进行的快速测试中,我得到了-24
,但不要指望复制该特定结果。
这里的问题源于允许从String
到char *
的隐式转换。当我们尝试减去两个String
对象时,编译器会试图弄清楚我们的意思。由于它不能直接减去它们,它看它是否可以将它们转换为某种支持减法的类型——果然,char const *
支持减法,所以它将我们的String
对象都转换为char const *
,然后减去两个指针。
如果我们将该转化标记为explicit
:
explicit operator char const *() { return data.c_str(); }
。尝试减去两个String
对象的代码根本无法编译。
相同的基本思想可以/确实适用于explicit
构造函数,但是演示它的代码会变得更长,因为我们通常需要至少涉及几个不同的类。
- 应用于运算符而不是构造函数的显式关键字
- 如何通过 boost::p ython 重命名构造函数的关键字参数
- 在 new 关键字中,由默认构造函数初始化的类中的元素是否也使用 new 关键字在C++?
- 带有 "this" 关键字的 Java Copy 构造函数
- 为什么带有 const 关键字的构造函数可以工作,而没有它就不能工作?
- 当没有显式关键字与单参数构造函数一起使用时,编译器可以发出警告
- 使用 "using" 关键字继承基类的复制和移动构造函数
- 在构造函数中使用关键字 "this" 时定义复制构造函数
- 使用关键字继承构造函数时出乎意料的行为
- 显式关键字,移动构造函数和复制构造函数,并禁用移动和复制构造函数
- 构造函数使用多个参数时所需的显式关键字
- 构造函数显式关键字的使用
- 在结构构造函数中使用"this"关键字编译错误?-C++
- 模板类的构造函数在使用 new 关键字时调用类型构造函数
- 对单参数构造函数使用显式关键字
- 'explicit' g ++ 中的关键字对简单构造函数(不是复制/赋值构造函数)没有影响?
- 构造函数名称之前的关键字结构
- 为什么双参数构造函数以显式关键字开头
- 在std::auto_ptr的构造函数中使用' explicit '关键字有什么原因吗?
- 构造函数定义是否可以以 "class" 关键字为前缀?