在实现虚拟赋值运算符时,我遇到了一个有趣的问题。这不是编译器故障,因为g++ 4.1、4.3和VS 2005具有相同的行为。
基本上,虚拟operator=与任何其他虚拟函数在实际执行的代码方面有所不同。
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]),它会像普通虚拟函数一样执行。这种奇怪的行为有没有合理的解释?
a = static_cast<Base &>(b);
是避免使用 C 风格转换(可能会意外执行重新解释转换)的一种方法。 - M.M