views:

53

answers:

3

I have encountered the following problem which proved to me that I know far too little about the workings of C++.

I use a base class with pure virtual functions

class Base
    ...

and a derived classes of type

class Derived : public Base{
private:
  Foo* f1;
 ...

Both have assignment operators implemented. Among other things, the assignment operator for Derived copies the data in f1. In my code, I create two new instances of class Derived

Base* d1 = new Derived();
Base* d2 = new Derived();

If I now call the assignment operator

*d1 = *d2;

the assignment operator of Derived is not called, and the data in f1 is not copied! It only works if I do

*dynamic_cast<Derived*>(d1) = *dynamic_cast<Derived*>(d2);

Can someone explain why the assignment operators are not overloaded?

Thanks!

A: 

For virtual to work you need the same signature. So if your operator= works on a const Derived& parameter in your Derived class that doesn't match the one that is working on a const Base& parameter in your base class.

This means that you can accomplish polymorphism but you need to have an operator=(const Base&) in your derived class to do so.

Brian R. Bondy
Hans
@Hans: Yes that's fine.
Brian R. Bondy
+3  A: 

It's hard to say without seeing the relevant code. Here's an example that works:

#include <iostream>

using namespace std;

class A {
  public:
    virtual A& operator=(A& a) {}
};

class B : public A {
  public:
    B& operator=(A& a) { cout << "B" << endl; }
};

int main() {
  A* foo = new B();
  A* bar = new B();
  *foo = *bar;
  return 0;
}

This will print B when run.

Things that you might be doing wrong:

  1. You might have forgotten to make operator= virtual in the base class.
  2. You might have given the child's class operator= as signature that's more restrictive than that of the parent's operator=, so you're not actually overriding the parent's definition. For example if you change B& operator=(A& a) { cout << "B" << endl; } to B& operator=(B& a) { cout << "B" << endl; } in the example above, it will no longer print B.
sepp2k
+1  A: 

I have some alternate perspective on the accepted answer. This is basically More Effetive C++ Item 33. So even though the accepted solution works, I think it is important to bring out the dangers involved in making assignment operator virtual!

class Animal {
public:
    virtual Animal& operator=(const Animal& rhs);
};

class Lizard: public Animal {
public:
    virtual Lizard& operator=(const Animal& rhs);
};

class Chicken: public Animal {
public:
    virtual Chicken& operator=(const Animal& rhs);
};

int main(){
    Lizard l;
    Chicken c;

    Animal *pL = &l;
    Animal *pC = &c;

    *pL = *pC;             // assigns chicken to a lizard.
}
Chubsdad