While having fun with applying an online assignment operator I've ended having a funny behavior. It's not a compiler glitch, since g++ 4.1, 4.3 and Versus 2005 share exactly the same behavior.

Essentially, the virtual operator= reacts in a different way than every other virtual function regarding the code that's really being performed.

struct Base amplifier f( Base const &lifier ) amplifier)" << std::endl

      return *this

   

   virtual Base&lifier operator=( Base const &lifier ) amplifier)" << std::endl

      return *this

   



struct Derived : public Base amplifier f( Base const &lifier ) amplifier)" << std::endl

      return *this

   

   virtual Base&lifier operator=( Base const &lifier ) amplifier )" << std::endl

      return *this

   



int primary() results: Derived::f(Base const &lifier) (expected result)

   a = b    // [1] results: Base::operator=(Base const &lifier)

   Base &lifier ba = a

   Base &lifier bb = b

   ba = bb  // [2] results: Derived::operator=(Base const &lifier)

   Derived &lifier da = a

   Derived &lifier db = b

   da = db  // [3] results: Base::operator=(Base const &lifier)

   ba = da  // [4] results: Derived::operator=(Base const &lifier)

   da = ba  // [5] results: Derived::operator=(Base const &lifier)



The result would be that the virtual operator= includes a different behavior than every other virtual function with similar signature ([] in comparison to [1]), by calling the bottom version from the operator when known as through real Derived objects ([1]) or Derived references ([3]) although it does perform like a regular virtual function when known as through Base references ([2]), or when either the lvalue or rvalue are Base references and also the other a Derived reference ([4],[5]).

Can there be any sensible explanation for this odd behavior?

Here's the way it goes:

Basically change [1] to

a = *((Base*)&b)

then things work how you expect. There's an instantly produced assignment operator in Derived that appears such as this:

Derived&lifier operator=(Derived const &lifier that) people using assignment operator, for instance

    foo = that.foo

    bar = that.bar

    return *this



Inside your example compilers have sufficient info to reckon that a and b are of type Derived and they also opt for the instantly produced operator above that calls yours. That's the way you got [1]. My pointer casting forces compilers to get it done the right path, because I tell compiler to "forget" that b is of type Derived so it uses Base.

Other results could be described exactly the same way.

IMO, there's no assignment operator defined for Derived class. Hence, compiler synthesizes one and internally base class assignment operator is known as from that synthesized assignment operator for Derived class.

virtual Base&lifier operator=( Base const &lifier ) //isn't assignment operator for Derived

Hence, a = b // [1] results: Base::operator=(Base const &lifier)

In Derived class, the bottom class assignment operator continues to be overridden and therefore, the overridden method will get an entry in virtual table from the Derived class. Once the technique is invoked via reference or pointers then Derived class overridden method will get known as because of VTable entry resolution at run time.

ba = bb  // [2] results: Derived::operator=(Base const &lifier)

==>internally ==> (Object->VTable[Assignement operator]) Obtain the entry for assignment operator in VTable from the class that the item goes and invoke the technique.

Folks who wants offer an appropriate operator= (i.e. correct return and argument types), the default operator= is supplied through the compiler which overrides any user-defined one. Inside your situation it'll call the bottom::ownerEquals (Base const&lifier ) before copying the Derived people.

Take a look link for particulars on operator= being made virtual.