Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does virtual assignment behave differently than other virtual functions of the same signature?

Tags:

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?

like image 401
David Rodríguez - dribeas Avatar asked Jun 09 '09 10:06

David Rodríguez - dribeas


People also ask

What is difference between virtual function and normal function?

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).

What are the characteristics of virtual function?

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.

What is a virtual function why it is used explain with a suitable example?

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.

What is the advantage of virtual 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.


1 Answers

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.

like image 69
Jasiu Avatar answered Oct 09 '22 20:10

Jasiu