赋值运算符的布尔和字符串重载 (C++)

Posted

技术标签:

【中文标题】赋值运算符的布尔和字符串重载 (C++)【英文标题】:Boolean and String Overloads of the Assignment Operator (C++) 【发布时间】:2013-02-08 12:50:32 【问题描述】:

我正在定义赋值运算符的多个重载,如下所示:

Foo.h

class Foo

private:
    bool my_bool;
    int my_int;
    std::string my_string;
public:
    Foo& operator= (bool value);
    Foo& operator= (int value);
    Foo& operator= (const std::string& value);
;

Foo.cpp

// Assignment Operators.
Foo& Foo::operator= (bool value) my_bool = value; return *this;
Foo& Foo::operator= (int value) my_int = value; return *this;
Foo& Foo::operator= (const std::string& value) my_string = value; return *this;

这是我的 main.cpp(请参阅标记为 SURPRISE 的评论):

Foo boolFoo;
Foo intFoo;
Foo stringFoo;

// Reassign values via appropriate assignment operator.
boolFoo = true;                // works...assigned as bool
intFoo = 42;                   // works...assigned as int
stringFoo = "i_am_a_string";   // SURPRISE...assigned as bool, not string

std::string s = "i_am_a_string";
stringFoo = s;                 // works...assigned as string

// works...but awkward
stringFoo = static_cast<std::string>("i_am_a_string");

问题:有人能告诉我为什么在布尔上下文中评估未转换的字符串文字吗?

【问题讨论】:

@Mooing Duck:为什么要删除构造函数?我添加它们是为了有意表明一个变量可以通过构造函数初始化,然后通过赋值重新分配操作员。 (正如我在其他 SO 帖子中看到的,有时您需要both。) 由于Good questions have a short self contained compilable example 和your code could be significantly shorter and simpler and still reproduce the problem,我对代码进行了修剪。我第一次没有阅读您的大部分问题,因为其中的代码 far 太多,而且我(正确地)猜到其中大部分与您的问题无关。 @Mooing Duck:是的,我原则上非常同意,并且在将构造函数添加到我的示例时确实考虑了这一点。但我会在这里听从你的判断。但是,我希望看到我的评论的任何人都知道要考虑相关的构造函数。 我不明白,你为什么希望他们考虑相关的构造函数?构造函数可能与类似的问题相关,但它们与这个问题完全无关。如果他们看到构造函数,那可能会让人们认为这与他们的构造函数有关。 @Mooing Duck:感谢您继续推动。现在真正让我陷入困境的是Foo(std::string&amp;)Foo(char *) 的方法签名完全不同,无论Foo 是构造函数还是任何其他方法。所以,我现在意识到我在理解上的差距确实超出了我所看到的赋值运算符(我发布的问题的主题)。 【参考方案1】:

C++ 标准在第 13.3 章中定义了重载解析规则,您可以在其中找到:

13.3.3.2 对隐式转换序列进行排名[over.ics.rank]

2比较隐式转换序列的基本形式时(定义见13.3.3.1)

— 标准转换序列 (13.3.3.1.1) 是比用户定义的转换序列或省略号转换序列更好的转换序列,并且

- 用户定义的转换序列 (13.3.3.1.2) 是比省略号转换序列 (13.3.3.1.3) 更好的转换序列。

这意味着编译器将首选从字符串文字到boolint(如果可用)的标准转换序列。现在,哪些标准转换是相关的?在您的情况下,这两个是相关的:

4.2 数组到指针的转换[conv.array]

1 “N T 的数组”或“T 的未知边界数组”类型的左值或右值可以转换为“指向 T 的指针”类型的纯右值。结果是指向数组第一个元素的指针。

此转换将const char[N] 类型的字符串文字转换为const char*。第二个是:

4.12 布尔转换 [conv.bool]

1 算术、无范围枚举、指针或指向成员类型的指针的纯右值可以转换为bool 类型的纯右值。零值、空指针值或空成员指针值转换为false;任何其他值都将转换为truestd::nullptr_t 类型的纯右值可以转换为bool 类型的纯右值;结果值为false

这就是指针转换为bool的原因。由于存在标准转换序列,因此不使用用户定义的到std::string 的转换。

为了解决您的问题,我建议您添加另一个采用 const char* 的重载版本,并将调用转发到 const std::string&amp; 重载。

【讨论】:

谢谢,丹尼尔!对我来说,另一个教训是字符串文字映射到char *(通过char[N]),不是 std::string @DavidRR:应该是const char*const char[N],但是是的。【参考方案2】:

丹尼尔是对的。

简短的回答是 std::string 不是内置类型,因此没有任何神奇的优惠待遇。不幸的是,像"hi world" 这样的字符串字面量的类型不是 std::string,而是一种指针类型,它更容易转换为内置类型bool,而不是“用户自定义" 类型std::string

基本上,答案是:欢迎使用 C++。

是的,我知道,它来自 standard 库,不,没关系。

【讨论】:

我认为有人投了反对票,因为最后一句话听起来有点刻薄。 @Mooing:如果它很尖刻,那么它在 C++ 中就是尖利的。如果有人把那个当成了个人,那么,他们是我无法帮助的。 作为提问者,我对“欢迎使用 C++”一点也不生气。我发现 C++ 与 Java 和 C# 完全不同。使用 C++,似乎有更多陷入麻烦的机会...... 或者换句话说,额外的灵活性伴随着额外的责任。 你的意思是:With great power comes great responsibility :)

以上是关于赋值运算符的布尔和字符串重载 (C++)的主要内容,如果未能解决你的问题,请参考以下文章

c++中拷贝构造函数和赋值运算符重载本质上一样么

c++中为啥赋值运算符重载返回类型是引用

c++ 拷贝构造函数与赋值运算符重载函数的区别是

c++重载赋值操作符的返回值是啥?

C++重载赋值运算符

C++重载赋值运算符