1)以下两者有何不同:
complex& operator = (const complex& c);
并且
complex operator = (complex c);
2) 如果我在第二种情况下定义了复制构造函数,它们是否相同?
complex::complex (const complex& c){
//code
}
3) const的作用是什么?
1)以下两者有何不同:
complex& operator = (const complex& c);
并且
complex operator = (complex c);
2) 如果我在第二种情况下定义了复制构造函数,它们是否相同?
complex::complex (const complex& c){
//code
}
3) const的作用是什么?
您想要链接赋值吗?返回* this
。
a = b = c; // Chained assignment
C++中的默认赋值支持链式操作,因此保持这个规则是一个好主意。
为了支持这种类型的赋值,每个操作都必须返回对 *this
的引用或返回一个副本:
complex& operator = (const complex& c)
{
// do assignment
return *this;
}
或者
complex operator = (const complex& c)
{
// do assignment
return *this;
}
但是,这个简单的工作应该是轻便高效的。如果没有RVO或移动可用,则更喜欢返回引用而不是副本。
我喜欢返回引用的另一个原因是为了摆脱我心中的困惑。看看以下两种情况:
// Returning a reference
a = 1;
b = 2;
c = 3;
(a = b) = c;
在赋值后,a=3
,b=2
,c=3
。因为首先b
分配给a
并返回一个对a
的引用,然后c
分配给该引用并再次更改a
。
// Returning a copy
a = 1;
b = 2;
c = 3;
(a = b) = c;
a=2
b=2
c=3
。因为首先b
分配给a
并返回一个临时副本,然后c
分配给该临时对象(对a
或b
没有影响)。(a=b)=c
,C++程序员会期望得到第一个结果。const
关键字:const
来保护不受意外更改的对象。1) 第一个版本是惯用的C++版本。它表示它接受参数的引用(而不是复制),并将返回对一个复杂对象的引用(而不是复制),通常是正在分配的对象(即*this
)。
第二个版本可以工作,但它会产生不必要的副本,并且您无法调用被分配对象上的函数,例如:(a = b).dosth()
,因为它返回了一个不同的对象。我的意思是它会编译,但它会在一个临时对象上调用dosth
。
2) 它们从未相同,但是如果您没有可访问的复制构造函数(或者有时是移动构造函数),第二个版本将无法工作。
3) const
是一个承诺,表明您不会修改参数。因此,在a = b
中,您不希望修改b
,并且const
强制执行该规则。在第二个版本(按值传递)中,您不需要它,因为您无论如何都不能修改它,因为它只是一份副本。
complex operator=(complex c);
参数c
作为原始副本传入。对于像int
这样的简单数据类型,这并不重要,但如果是complex
,那么这可能会导致不必要的分配/释放和影响性能。
通过引用传递,如下:
complex& operator=(complex& c);
这意味着传递给运算符的对象并没有被复制。
第二个区别在于它们返回的内容。运算符的正确形式是返回对自身的引用。你提供的第一种形式实际上返回了对象的副本,这可能会导致效率低下。
最后,再次强调,运算符的正确形式应该将输入对象作为一个const
引用。这更多是一个风格问题,而不是性能问题——但人们不应该合理地期望赋值运算符修改输入对象,指定它为const
可以防止这种情况发生。
因此,总结一下,
complex& operator=(const complex& c);
是正确的形式。
operator=
的情况下,按值传递通常是完全可以的,特别是如果对象很大(但可以便宜地交换)。然而,在complex
类的情况下,可能不是这种情况。 - Konrad Rudolph它们并不相同,第一个传递引用,因此对象在内存中保持不变,而第二个将需要复制构造函数,因为complex
对象将在函数内部复制进出。第一个是规范的,也是你想要的,第二个没有被使用,因为它是不必要的浪费。
const
是一种表达“我保证不会改变 c
!所以不用担心它!”的方式。这允许用户通过引用提供实际类(在您的情况下是 complex
),而不必担心它会意外更改。
“引用” - 通过添加 &
符号选择 - 意味着此函数实际上使用用户提供的相同对象,来自相同的内存。由于它正在使用相同的对象,因此重要的是您承诺不更改该对象。
没有 &
- 您的第二个示例 - 您不传递相同的对象,而是传递该对象的 副本。因此,const
是不必要的(尽管仍然合法),因为用户不关心您是否更改了副本。
区别?时间(对于大型类还有内存)。如果将对象的引用传递给函数 - 您无需复制该对象。这可以节省您的时间(复制对象所需的时间)和内存(对象需要的内存)。
operator=
并在复制构造函数中使用它(通过执行 *this=other
)。这比另一种方式要好得多(因为它不需要高效的交换,并且不会创建3个不同的对象)。 - rabensky
operator=
会看到它有足够的内存来存储新值,因此它不需要分配内存。而你的复制-交换语义将进行分配(为新对象),复制,交换和释放内存。这要慢得多! - rabenskyconst reference
输入参数可以被绑定到一个临时变量上,而且如果代码被内联,它会被简单地替换为该临时变量或输入的非临时变量。 - rabensky