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.
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 &) }
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?
Non-virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object. In contrast, virtual member functions are resolved dynamically (at run-time).
Properties of virtual functionVirtual functions are resolved during run time resolved during run time hence it is a dynamic binding. Virtual functions are member functions of a class. Virtual functions are declared with the keyword virtual. Virtual function takes a different functionality in the derived class.
A virtual function is a member function that you expect to be redefined in derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.
The main advantage of virtual functions are that they directly support object oriented programming. When you declare a function as virtual you're saying that exactly what code is executed depends on the type of the object you call it against. you can't tell exactly what code path it's going to follow.
Here's how it goes:
If I change [1] to
a = *((Base*)&b);
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; }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With