Dav*_*eas 22 c++ inheritance virtual-functions assignment-operator
在玩实现虚拟赋值运算符的过程中,我以一种有趣的行为结束了.它不是编译器故障,因为g ++ 4.1,4.3和VS 2005共享相同的行为.
基本上,虚拟运算符=与实际执行的代码相比,其行为与任何其他虚拟函数不同.
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 &)
}
Run Code Online (Sandbox Code Playgroud)
结果是虚拟运算符=与具有相同签名的任何其他虚函数([0]与[1]相比)具有不同的行为,通过在通过实际派生对象调用时调用运算符的基本版本([1] )或派生引用([3]),当它通过基础引用([2])调用时,或者当左值或右值是基础引用而另一个是派生引用([4]时,它确实作为常规虚函数执行) [5]).
对这种奇怪的行为有什么明智的解释吗?
Jas*_*siu 14
这是怎么回事:
如果我改变[1]
a = *((Base*)&b);
Run Code Online (Sandbox Code Playgroud)
然后事情就像你期望的那样.有一个自动生成的赋值运算符Derived
,如下所示:
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;
}
Run Code Online (Sandbox Code Playgroud)
在您的示例中,编译器有足够的信息来猜测a
并且b
是类型的Derived
,因此他们选择使用上面自动生成的运算符来调用您的运算符.这就是你得到的[1].我的指针强制转换强制编译器按照你的方式执行,因为我告诉编译器"忘记"它b
是类型的Derived
,所以它使用Base
.
其他结果可以用同样的方法解释.
在这种情况下有三个operator =:
Base::operator=(Base const&) // virtual
Derived::operator=(Base const&) // virtual
Derived::operator=(Derived const&) // Compiler generated, calls Base::operator=(Base const&) directly
Run Code Online (Sandbox Code Playgroud)
这解释了为什么看起来像Base :: operator =(Base const&)在[1]中被称为"虚拟".它是从编译器生成的版本调用的.这同样适用于案例[3].在情况2中,右侧参数'bb'具有类型Base&,因此无法调用Derived :: operator =(Derived&).
归档时间: |
|
查看次数: |
3483 次 |
最近记录: |