C++ 重载赋值运算符
C++ overload assignment operator
我目前正在为赋值运算符而苦恼。我一直在想念一些东西。
你能帮帮我吗?
在这里查看
https://godbolt.org/z/rfvTqcjoT
class SpecialFloat
{
public:
explicit SpecialFloat(const float f);
SpecialFloat& operator=(const float f);
private:
float m_float;
};
SpecialFloat::SpecialFloat(const float f):
m_float(f)
{
}
SpecialFloat& SpecialFloat::operator=(const float f)
{
m_float = f;
}
int main()
{
SpecialFloat f = 1.0f;
}
为什么我的运算符重载不起作用?
<source>(27): error C2440: 'initializing': cannot convert from 'float' to 'SpecialFloat'
<source>(27): note: Constructor for class 'SpecialFloat' is declared 'explicit'
或者赋值运算符可以不接受自定义类型吗?
行SpecialFloat f = 1.0f;
无法执行从1.0f
到f
的赋值,因为f
还不存在。我们只是在创造它。
如果你写 SpecialFloat f{0.0f}; f = 1.0f
[Demo].
就可以了
行 SpecialFloat f = 1.0f;
正在做 copy initialization (1)。
Initializes an object from another object.
Syntax
T object = other; (1)
在您的代码中 T
是 SpecialFloat
,一个 class 类型,而 other
是一个 float
(不是 T
或派生的来自 T
).
The effects of copy initialization are:
...
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T [...] user-defined conversion sequences that can convert from the type of other to T are
examined and the best one is selected through overload resolution. The result of the conversion, which is a rvalue temporary [...] of the cv-unqualified version of T if a converting constructor was used, is then used to direct-initialize the object.
应检查从 float
到 SpecialFloat
的 User-defined 转换。但是,copy-initialization.
不考虑显式构造函数
Notes
Copy-initialization is less permissive than
direct-initialization: explicit constructors are not converting
constructors and are not considered for copy-initialization.
解决此问题的一种方法是使用 direct initialization, and, if possible, with braces instead of parentheses, i.e. SpecialFloat f{1.0f};
[Demo]。
有一个 C++ 核心指南建议 preferring the {}-initializer syntax。
此外,声明 single-argument constructors explicit 是一般建议,因此我会将 user-declared 构造函数保持为显式。
另一种方法是通过删除 user-declared 构造函数并使用 aggregate initialization, SpecialFloat f = {1.0f};
[Demo].
使 SpecialFloat
class 成为聚合
最后,正如其他人评论的那样,请注意赋值运算符的签名是 SpecialFloat& operator=(const float f)
,这表明 SpecialFloat&
必须被 returned。所以首先,用 m_float = f;
更新对象;然后,return 它与 return *this;
.
[编辑]
我刚从 Arthur O'Dwyer 的文章中看到这篇文章,The Knightmare of Initialization in C++ 他基本上赞成复制初始化而不是用大括号直接初始化,以提高代码的可读性。
Simple guidelines for variable initialization in C++:
- Use = whenever you can.
- Use initializer-list syntax {} only for element initializers (of containers and aggregates).
- Use function-call syntax () to call a constructor, viewed as an object-factory.
Thus:
int i = 0;
std::vector<int> v = {1, 2, 3, 4};
Widget w(name, price, quantity);
此外,他建议将复制初始化与 Almost Always Auto 样式结合起来。回到最初的 OP 问题,这将使我们能够保持 SpecialFloat
class 不变并写入 auto f = SpecialFloat{1.0f};
[Demo].
他承认他的指南与前面提到的 preferring the {}-initializer syntax 的 C++ 核心指南冲突。
有以下几个问题。
SpecialFloat f = 1.0f;
表示您正在尝试将浮点值分配给 SpecialFloat 对象。如果 SpecialFloat 的构造函数采用浮点参数并且构造函数未标记为显式,则此方法有效。但是在您的代码中,您将构造函数标记为显式。所以对象没有被创建并抛出错误。如果您想了解有关显式构造函数的更多信息,请阅读 What does the explicit keyword mean?
赋值运算符重载函数应该return SpecialFloat 对象。你没有 returning 任何错误的东西。它应该 return SpecialFloat 对象如下。
SpecialFloat& SpecialFloat::operator=(const float f)
{
m_float = f;
return *this;
}
你对赋值运算符重载函数调用的理解是错误的。当您尝试将对象分配给已创建的对象时,将调用赋值运算符重载函数。
SpecialFloat f = 1.0f;
以上语句试图创建一个对象。所以在这种情况下不会调用赋值运算符重载函数。
我目前正在为赋值运算符而苦恼。我一直在想念一些东西。 你能帮帮我吗?
在这里查看 https://godbolt.org/z/rfvTqcjoT
class SpecialFloat
{
public:
explicit SpecialFloat(const float f);
SpecialFloat& operator=(const float f);
private:
float m_float;
};
SpecialFloat::SpecialFloat(const float f):
m_float(f)
{
}
SpecialFloat& SpecialFloat::operator=(const float f)
{
m_float = f;
}
int main()
{
SpecialFloat f = 1.0f;
}
为什么我的运算符重载不起作用?
<source>(27): error C2440: 'initializing': cannot convert from 'float' to 'SpecialFloat'
<source>(27): note: Constructor for class 'SpecialFloat' is declared 'explicit'
或者赋值运算符可以不接受自定义类型吗?
行SpecialFloat f = 1.0f;
无法执行从1.0f
到f
的赋值,因为f
还不存在。我们只是在创造它。
如果你写 SpecialFloat f{0.0f}; f = 1.0f
[Demo].
行 SpecialFloat f = 1.0f;
正在做 copy initialization (1)。
Initializes an object from another object.
Syntax
T object = other; (1)
在您的代码中 T
是 SpecialFloat
,一个 class 类型,而 other
是一个 float
(不是 T
或派生的来自 T
).
应检查从The effects of copy initialization are:
...
If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T [...] user-defined conversion sequences that can convert from the type of other to T are examined and the best one is selected through overload resolution. The result of the conversion, which is a rvalue temporary [...] of the cv-unqualified version of T if a converting constructor was used, is then used to direct-initialize the object.
float
到 SpecialFloat
的 User-defined 转换。但是,copy-initialization.
不考虑显式构造函数Notes
Copy-initialization is less permissive than direct-initialization: explicit constructors are not converting constructors and are not considered for copy-initialization.
解决此问题的一种方法是使用 direct initialization, and, if possible, with braces instead of parentheses, i.e. SpecialFloat f{1.0f};
[Demo]。
有一个 C++ 核心指南建议 preferring the {}-initializer syntax。
此外,声明 single-argument constructors explicit 是一般建议,因此我会将 user-declared 构造函数保持为显式。
另一种方法是通过删除 user-declared 构造函数并使用 aggregate initialization, SpecialFloat f = {1.0f};
[Demo].
SpecialFloat
class 成为聚合
最后,正如其他人评论的那样,请注意赋值运算符的签名是 SpecialFloat& operator=(const float f)
,这表明 SpecialFloat&
必须被 returned。所以首先,用 m_float = f;
更新对象;然后,return 它与 return *this;
.
[编辑]
我刚从 Arthur O'Dwyer 的文章中看到这篇文章,The Knightmare of Initialization in C++ 他基本上赞成复制初始化而不是用大括号直接初始化,以提高代码的可读性。
Simple guidelines for variable initialization in C++:
- Use = whenever you can.
- Use initializer-list syntax {} only for element initializers (of containers and aggregates).
- Use function-call syntax () to call a constructor, viewed as an object-factory.
Thus:
int i = 0; std::vector<int> v = {1, 2, 3, 4}; Widget w(name, price, quantity);
此外,他建议将复制初始化与 Almost Always Auto 样式结合起来。回到最初的 OP 问题,这将使我们能够保持 SpecialFloat
class 不变并写入 auto f = SpecialFloat{1.0f};
[Demo].
他承认他的指南与前面提到的 preferring the {}-initializer syntax 的 C++ 核心指南冲突。
有以下几个问题。
SpecialFloat f = 1.0f;
表示您正在尝试将浮点值分配给 SpecialFloat 对象。如果 SpecialFloat 的构造函数采用浮点参数并且构造函数未标记为显式,则此方法有效。但是在您的代码中,您将构造函数标记为显式。所以对象没有被创建并抛出错误。如果您想了解有关显式构造函数的更多信息,请阅读 What does the explicit keyword mean?
赋值运算符重载函数应该return SpecialFloat 对象。你没有 returning 任何错误的东西。它应该 return SpecialFloat 对象如下。
SpecialFloat& SpecialFloat::operator=(const float f)
{
m_float = f;
return *this;
}
你对赋值运算符重载函数调用的理解是错误的。当您尝试将对象分配给已创建的对象时,将调用赋值运算符重载函数。
SpecialFloat f = 1.0f;
以上语句试图创建一个对象。所以在这种情况下不会调用赋值运算符重载函数。