在 c++ In Plain English, Second Edition(1999)中,书中有一节说可以使用"="在调用正确的构造函数时进行初始化。就像给定一个类CStr
和一个构造函数CStr(char*)
,书上是这样说的:
类似地,最后一个声明调用构造函数CStr(char*):CStr name3 = "Jane Doe";
我想用std::string
构造函数尝试同样的事情。我的部分测试代码是这样的:
using namespace std;
class CStr {
private:
string name;
public:
CStr(string s): name(s) {}
};
int main() {
CStr name3 = "Jane Doe";
}
但是,当我编译时,在name3初始化中得到一个错误:
"请求从'const char[9]'转换为'CStr'非标量类型"。
为什么不将CStr::name初始化为字符串s = "Jane Doe"工作?像string nameTest{"Jane Doe"};
这样的字符串测试工作了,所以我认为这也会起作用。也许这本书太旧了(这是我现在唯一的一本书),但我认为错误更多的是在我身上。
你的书很旧,但基本上是对的[1]注意,"Jane Doe"
不是std::string
,而是const char[9]
(并且可能衰减到const char*
)。因此对于CStr name3 = "Jane Doe";
,需要进行两次用户定义的转换(即const char*
-> std::string
和std::string
-> CStr
),这在一次隐式转换中是不允许的。
这也证明了如果CStr
的构造以const char*
作为参数,CStr name3 = "Jane Doe";
也可以正常工作,因为它只需要进行一次用户定义的转换。
您可以通过添加显式转换来减少一个:
CStr name3 = std::string("Jane Doe");
或直接使用字符串字面值(c++ 14起),其类型为std::string
:
CStr name3 = "Jane Doe"s;
为什么不将CStr::name初始化为字符串s = "Jane Doe"工作?像
string nameTest{"Jane Doe"};
这样的字符串测试可以工作,所以我认为这也可以工作。
你的问题不够清楚,无论如何,std::string nameTest{"Jane Doe"};
工作是因为,(取决于你的误解,)(1)这里只需要一个隐式转换(const char*
-> std::string
;(2) string nameTest{"Jane Doe"};
为直接初始化。
正如@LightnessRacesinOrbit评论的那样,直接初始化(即CStr name3("Jane Doe")
或CStr name3{"Jane Doe"}
(自c++ 11起))可以正常工作,而CStr name3 = "Jane Doe";
是复制初始化,它们在某些方面有所不同:
此外,复制初始化中的隐式转换必须直接从初始化式生成T,而,例如类型进行隐式转换T的构造函数参数的初始化式
struct S { S(std::string) {} }; // implicitly convertible from std::string S s("abc"); // OK: conversion from const char[4] to std::string S s = "abc"; // Error: no conversion from const char[4] to S S s = "abc"s; // OK: conversion from std::string to S
这意味着,对于复制初始化,实参Jane Doe
(const char*
)必须直接转换为CStr
;因为需要两次用户定义的转换,所以代码被拒绝。对于直接初始化,可以将Jane Doe
(const char*
)转换为CStr
的构造函数的参数,即先转换为std::string
,然后再调用CStr::CStr(std::string)
来构造对象。
[1] "Jane Doe"
是一个C风格的字符串字面值,它是const,从c++ 11开始,将它赋值给char*
是非法的,例如
char * pc = "Jane Doe"; // illegal
const char * pcc = "Jane Doe"; // fine