我有一个类Number
,它代表一个双点,后面有两位数。在我重载=
运算符之前,我运行了一些测试并且有点困惑:
int main(int argc, char **argv) {
Number *w = new Number(1.111);
Number *q = new Number(3.444);
*w = *q;
std::cout << w->GetNumber() <<std::endl;
delete q;
std::cout << w->GetNumber() <<std::endl;
Number e(5.555);
Number t = e;
std::cout <<t.GetNumber() <<std::endl;
}
输出
3.44
3.44
5.55
当'='没有超载时,'='对用户定义对象的默认操作是什么?
我的印象是写作时:
*w = *q;
w
指向q
(与Java一样)。但是,在我的示例中,我删除了q
,而w
仍然具有正确的值。
无论如何,当我使用重载=
和 重载=
时,我的作业得分相同。
答案 0 :(得分:3)
赋值运算符的默认操作是成员赋值:
class Foo
{
int i;
std::string s;
Bar b;
public:
Foo& operator=(const Foo& that)
{
i = that.i;
s = that.s;
b = that.b;
return *this;
}
};
如果这正是您所需要的,您不必手动重载operator=
。
如果你有指针成员,只复制指针,而不是复制,这可能会造成严重破坏。在这种情况下使用RAII类型(如std::vector
)或通过声明复制构造函数和赋值运算符private
或通过继承boost::noncopyable
来禁用复制。
请注意Number t = e;
不调用赋值运算符,因为还没有要分配的对象。而是调用复制构造函数,它默认执行成员复制构造:
Foo(const Foo& that) : i(that.i), s(that.s), b(that.b)
{
}
因为您可能会问:冒号之后的东西被称为初始化列表。初衷和赋值是C ++中两个截然不同的概念,这一点不容小觑。
答案 1 :(得分:2)
它生成对象的副本(深层副本),即q
对象的内容被复制到w
。如果您没有提供自己的复制构造函数 - 赋值运算符对,那么编译器将自动为您生成一个,它将源对象的每个元素复制到目标对象的元素。创建此副本后,使用原始对象执行的操作无关紧要。
答案 2 :(得分:2)
* p = * q相当于
(*p).operator=(*q);
默认赋值运算符执行以下操作:(我尝试将其简称但我无法在准确性和简洁性方面超越标准,因此引用它)
X类的隐式定义的复制赋值运算符执行其子对象的成员分配。首先按照它们在base-specifierlist中的声明顺序分配X的直接基类,然后按照它们在类定义中声明的顺序分配X的直接非静态数据成员。每个子对象都以适合其类型的方式分配:
- 如果子对象是类类型,则使用该类的复制赋值运算符(就好像通过显式限定;即忽略更多派生类中的任何可能的虚拟覆盖函数);
- 如果子对象是一个数组,则以适合于元素类型的方式分配每个元素;
- 如果子对象是标量类型,则使用内置赋值运算符。
如您所见,左侧对象没有开始引用右侧对象。
答案 3 :(得分:1)
默认operator =
执行对象的成员副本到目的地。
*w = *q
将*q
的值分配给*w
;
w = q
使w指向与q相同的对象,但它泄漏了w。