问题描述
在尝试实现虚拟赋值运算符时,我以一个有趣的行为结束.这不是编译器故障,因为 g++ 4.1、4.3 和 VS 2005 具有相同的行为.
While playing with implementing a virtual assignment operator I have ended with a funny behavior. It is not a compiler glitch, since g++ 4.1, 4.3 and VS 2005 share the same behavior.
基本上,就实际执行的代码而言,virtual operator= 的行为与任何其他虚函数不同.
Basically, the virtual operator= behaves differently than any other virtual function with respect to the code that is actually being executed.
struct Base {
virtual Base& f( Base const & ) {
std::cout << "Base::f(Base const &)" << std::endl;
return *this;
}
virtual Base& operator=( Base const & ) {
std::cout << "Base::operator=(Base const &)" << std::endl;
return *this;
}
};
struct Derived : public Base {
virtual Base& f( Base const & ) {
std::cout << "Derived::f(Base const &)" << std::endl;
return *this;
}
virtual Base& operator=( Base const & ) {
std::cout << "Derived::operator=( Base const & )" << std::endl;
return *this;
}
};
int main() {
Derived a, b;
a.f( b ); // [0] outputs: Derived::f(Base const &) (expected result)
a = b; // [1] outputs: Base::operator=(Base const &)
Base & ba = a;
Base & bb = b;
ba = bb; // [2] outputs: Derived::operator=(Base const &)
Derived & da = a;
Derived & db = b;
da = db; // [3] outputs: Base::operator=(Base const &)
ba = da; // [4] outputs: Derived::operator=(Base const &)
da = ba; // [5] outputs: Derived::operator=(Base const &)
}
效果是虚拟运算符 = 与具有相同签名([0] 与 [1] 相比)的任何其他虚拟函数具有不同的行为,通过在通过真实派生对象调用时调用运算符的基础版本([1]) 或派生引用 ([3]) 当通过基引用 ([2]) 调用时,或者当左值或右值是基引用而另一个是派生引用 ([4],[5]).
The effect is that the virtual operator= has a different behavior than any other virtual function with the same signature ([0] compared to [1]), by calling the Base version of the operator when called through real Derived objects ([1]) or Derived references ([3]) while it does perform as a regular virtual function when called through Base references ([2]), or when either the lvalue or rvalue are Base references and the other a Derived reference ([4],[5]).
对这种奇怪的行为有什么合理的解释吗?
Is there any sensible explanation to this odd behavior?
推荐答案
流程如下:
如果我将 [1] 改为
If I change [1] to
a = *((Base*)&b);
然后事情会按照您期望的方式进行.Derived
中有一个自动生成的赋值运算符,如下所示:
then things work the way you expect. There's an automatically generated assignment operator in Derived
that looks like this:
Derived& operator=(Derived const & that) {
Base::operator=(that);
// rewrite all Derived members by using their assignment operator, for example
foo = that.foo;
bar = that.bar;
return *this;
}
在您的示例中,编译器有足够的信息来猜测 a
和 b
属于 Derived
类型,因此他们选择使用自动生成的上面的运算符调用你的.这就是你如何得到 [1].我的指针转换迫使编译器按照你的方式做,因为我告诉编译器忘记" b
是 Derived
类型,所以它使用 Base
>.
In your example compilers have enough info to guess that a
and b
are of type Derived
and so they choose to use the automatically generated operator above that calls yours. That's how you got [1]. My pointer casting forces compilers to do it your way, because I tell compiler to "forget" that b
is of type Derived
and so it uses Base
.
其他结果可以用同样的方式解释.
Other results can be explained the same way.
这篇关于为什么虚赋值的行为与相同签名的其他虚函数不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!