连接两个字符串文字

我正在读凯尼格的《加速 C + + 》。他写道: “新的想法是,我们可以使用 + 将一个字符串和一个字符串字面值连接起来——或者,就此而言,连接两个字符串(但不是两个字符串字面值)。

好吧,我想这是有道理的。现在我们来看两个单独的练习来说明这个问题。

以下定义是否有效?

const string hello = "Hello";


const string message = hello + ",world" + "!";

现在,我尝试执行上面的方法,它奏效了! 所以我很高兴。

然后我试着做下一个练习;

const string exclam = "!";


const string message = "Hello" + ",world" + exclam;

这招不管用。现在我明白了,这和你不能连接两个字符串有关,但是我不明白为什么我设法让第一个例子工作(不是“ ,world”和“ !”两个字符串?这不应该没用吗?)但不是第二次。

148124 次浏览

字符串(更准确地说,是 std::string)和字符原义之间的区别在于,后者没有定义 +运算符。这就是第二个例子失败的原因。

在第一种情况下,编译器可以找到一个合适的 operator+,第一个参数是 string,第二个是字符文字(const char*) ,因此它使用。这个操作的结果也是一个 string,所以当向它添加 "!"时,它会重复相同的技巧。

const string message = "Hello" + ",world" + exclam;

+运算符具有从左到右的结合性,因此等效的括号表达式是:

const string message = (("Hello" + ",world") + exclam);

正如您所看到的,两个字符串字面值 "Hello"",world"首先被“添加”,因此出现了错误。

连接的前两个字符串之一必须是 std::string对象:

const string message = string("Hello") + ",world" + exclam;

或者,您可以通过在表达式的这一部分加上圆括号来强制首先计算第二个 +:

const string message = "Hello" + (",world" + exclam);

您的第一个示例(hello + ",world" + "!")能够工作是有意义的,因为 std::string(hello)是最左边 +的参数之一。计算这个 +,结果是一个具有连接字符串的 std::string对象,然后将得到的 std::string"!"连接起来。


至于 为什么,您不能使用 +连接两个字符串文字,这是因为字符串文字只是一个字符数组(一个 const char [N],其中 N是字符串的长度加上一个空结束符)。在大多数上下文中使用数组时,它会转换为指向其初始元素的指针。

因此,当您尝试执行 "Hello" + ",world"时,您真正要做的是将两个 const char*添加到一起,这是不可能的(将两个指针添加到一起意味着什么?)如果是的话,它也不会做你想让它做的事。


请注意,可以通过将字符串文字放在一起来连接它们; 例如,下面两个是等价的:

"Hello" ",world"
"Hello,world"

如果您有一个很长的字符串文字,希望将其分解为多个行,那么这将非常有用。但它们必须是字符串文字: 这对 const char*指针或 const char[N]数组不起作用。

第二个示例不起作用,因为对于两个字符串文字没有 operator +。注意,字符串文字的类型不是 string,而是 const char *。你的第二个例子将工作,如果你修改它像这样:

const string message = string("Hello") + ",world" + exclam;

在情况1中,由于操作的顺序,您得到:

(hello + “ ,world”) + “ !”结果是 hello + “ !”,最后是 hello

在第二种情况下,正如詹姆斯指出的,你会得到:

(“ Hello”+ “ ,world”) + 感叹号,这是2个字符串文字的连接。

希望你明白:)

你应该时刻注意 类别

虽然它们看起来都像字符串,但是 "Hello"",world"字面意思

在您的示例中,exclam是一个 std::string对象。

C + + 有一个运算符重载,它接受一个 std::string对象并向其添加另一个字符串。当您将一个 std::string对象与一个文字连接起来时,它将为文字执行适当的强制转换。

但是如果您尝试连接两个文字,编译器将无法找到一个接受两个文字的运算符。

由于 C + + 14,你可以使用两个实际的 字符串字面值:

const string hello = "Hello"s;


const string message = hello + ",world"s + "!"s;

或者

const string exclam = "!"s;


const string message = "Hello"s + ",world"s + exclam;

如果我们写 字符串 s = “ hello”+ “ world!”; RHS 有以下类型 Const char [6] + const char [7]

现在两者都内置在数据类型中。 即,它们不再是 std: : string 类型。

那么,现在运算符重载的内置类型 应用由编译器定义的。 Ie-没有更多的操作符 + 被 std: : string 重载。

现在让我们来看看编译器是如何重载的

  • 两个 const char * 类型操作数的二进制运算符。

事实证明,编译器在这种情况下没有重载,因为它的意义更小。

即,添加两个“ const char *”在语义上是错误的,因为结果将是运行时的另一个 const char * 。 有很多原因可以解释为什么上述说法没有意义。

因此,任何运算符重载都有一个通用规则,那就是: 当操作符的所有操作数都是内置的时候,重载任何操作符。编译器设计人员会处理这种情况。在我们的确切问题中,std: : string 不能重载两个“ const 文本”,因为这个规则,编译器选择不实现 + 二进制运算符,因为它没有意义。

如果我们喜欢字符串的文字形式,我们可以像下面那样使用“ s”运算符。 字符串 p = “ hello”s + “ world!”

只要后缀是 s,意思就变了。 (超载操作员)