1

Suppose I have a base class which looks like this:

class Base
{
public:
   Base(){ baseMember = new int( 10 ); }

   Base &operator=( const Base &right )
   {
      baseMember = new int( *(right.baseMember) );
      return *this;
   }
protected:
   int *baseMember;
};

And now I want to have a Derived class which inherits from Base, and have a new pointer member called derivedMember:

class Derived : public Base
{
public:
   Derived():Base(){ derivedMember = new double( 10.1 ); }

   Derived &operator=( const Derived &right )
   { /*some implementation */ }
private:
   double *derivedMember;
};

How should I do the operator= implementation on the Derived class in a way which I can call the base class operator= and avoid having to rewrite the Base class operator= implementation on the Derived class? In simple words, how can I avoid having to do it:

Derived &operator=(const Derived &right )
{
   baseMember = new int( *(right.baseMember) ); //this is what I want to avoid rewriting
   derivedMember = new double( *(right.derivedMember) );
   return *this;
}
Richard Cook
  • 32,523
  • 5
  • 46
  • 71
Lucas
  • 13
  • 3
  • Why not use smart pointers? Code above has memory leaks – Ed Heal Oct 28 '15 at 19:04
  • Which leaks? I can't see it myself... – Lucas Oct 29 '15 at 02:30
  • Th constructor uses `new` to initialise `baseMember`. This gets overwritten in the assignment operator without the delete being used – Ed Heal Oct 29 '15 at 13:50
  • @EdHeal I see it now. I just skipped the delete thing to simply the example code. The class which I am working where this problem arose have the propper use of delete. Anyway, thank you for the tip. I will give a look on those smart pointers. – Lucas Oct 30 '15 at 01:06

1 Answers1

1

Like this:

Derived &operator=(const Derived &right )
{
    if (&right == this) { return *this; } // prevent assigning to self
    Base::operator=(right);
    delete derivedMember; // remember to release any assigned memory (assumes derivedMember is assigned a default of nullPtr)
    derivedMember = new double( *(right.derivedMember) );
    return *this;
}
GreatAndPowerfulOz
  • 1,767
  • 13
  • 19
  • Might as well add the test `if (&right == this) { return *this; }` at the start – Ed Heal Oct 28 '15 at 18:53
  • @EdHeal Yes, that's a good idea. – GreatAndPowerfulOz Oct 28 '15 at 18:55
  • @Lucas, remember to delete any already allocated memory in the assignment operator. Alternatively, you can say `*derivedMember = *right.derivedMember;` – GreatAndPowerfulOz Oct 28 '15 at 19:02
  • @Gread.And.Powerful.Oz Thank you for the reminder. The second tip is really useful, I don't know why it has not came to my mind :) About the answer itself, when calling the Base::operator, should I not use something like static_cast(right)? I think I saw it somewhere. – Lucas Oct 29 '15 at 02:28
  • @Lucas, there is no need to cast. You would only cast (maybe) when assigning to say a `void*` as in `void *foo = static_cast(myInstance);` Furthermore, there's nothing to cast, you're simply calling the base function. – GreatAndPowerfulOz Oct 29 '15 at 02:31
  • @Gread.And.Powerful.Oz But the Base::operator= uses an const Base object reference. So, are you saying the Derived object is type compatible with the Base object? I know the pointers are, but I have not tested it with references before. – Lucas Oct 29 '15 at 02:45
  • @Lucas, yes of course. You've subclassed `Derived` from `Base` so a reference to `Derived` is automagically convertible to a reference to `Base`. That is `Derived d; Base& b = d;` is valid code. So calling a `Base` function that takes a `Base&` parameter with a `Derived&` value is completely valid and normal C++. – GreatAndPowerfulOz Oct 29 '15 at 02:49
  • @Gread.And.Powerful.Oz Thank you, it is clear like water now. – Lucas Oct 29 '15 at 02:58