# Assignment operator & inheritance

This topic is 2157 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Consider the following code:

#include <iostream>

class Base
{
protected:
Base() {}
Base( const Base& that ) { *this = that; }
~Base() {}
public:
Base& operator=( const Base& that )
{
std::cout << "base assignment" << std::endl;
return *this;
}
};

class Derived : public Base
{
public:
Derived() {}
Derived( const Derived& that ) : Base( that ) { *this = that; }
~Derived() {}
Derived& operator=( const Base& that )
{
std::cout << "derived assignment" << std::endl;
return *this;
}
};

int main()
{

Derived test1, test2;

std::cout << "derived = derived" << std::endl;
test1 = test2;
std::cout << std::endl;

std::cout << "base = derived" << std::endl;
*static_cast<Base*>( &test1 ) = test2;
std::cout << std::endl;

std::cout << "derived = base" << std::endl;
test1 = *static_cast<Base*>( &test2 );
std::cout << std::endl;

std::cout << "base = base" << std::endl;
*static_cast<Base*>( &test1 ) = *static_cast<Base*>( &test2 );

return 0;
}

A few questions:

1. I noticed that operator overloads aren't overridden like normal methods. For instance, if I were to declare virtual Base& operator=( const Base& that ) in the base class, and try to override that in the derived class with Base& operator=( const Base& that ), then were to assign two derived objects, the base overload is still called rather than the derived overload. However, if I assign a base to derived, derived to base, or base to base, the operator overload in the derived class is called. Can someone explain this behavior?
2. Taking the example from question 1., if I remove the "virtual" keyword from the base declaration of the overload, it behaves differently. Only in the case of assigning a base object to a derived object is the derived operator called. In all other cases, the base operator is called. Can someone explain this behavior?
3. Is there a way for both overloads (in the base and derived class) to be called when an assignment occurs?

Thanks!

##### Share on other sites

You should always call the Base class version inside Derived class version (I hope you left it out cause its only a test).

You can define more than one operator= . You may therefore want to add a Derived& Derived::operator=(const Derived&) to have it called when you assign a Derived, because thats a better fit for overload resolution. Theoretically you could even add a Base& Base::operator=(const Derived&) if you forward declare Derived class, but it may not be a good thing to do.

When really getting a Derived but only having a Base reference, you could test if you actually got a Derived using a virtual helper method, to not loose data from attributes of Derived.

Btw., calling with a Base reference to a Derived may do different things than using a Base reference to a Base, depending on virtual methods, and you did not try that case.

Edited by wintertime

##### Share on other sites

That makes a lot of sense, thanks for clearing things up!

So in order to account for every possible way a user could copy this object, the whole thing should look like the following? Note that I declared Base' constructor and destructor protected, as I don't want base objects to be instantiated directly without being derived from.

#include <iostream>

class Base
{
protected:
Base() {}
~Base() {}
public:
virtual Base& operator=( const Base& that )
{
std::cout << "Base: Base& operator=( const Base& that )" << std::endl;
return *this;
}
};

class Derived : public Base
{
public:
Derived() {}
Derived( const Derived& that ) { *this = that; }
Derived( const Base& that ) { *this = that; }
~Derived() {}
Derived& operator=( const Base& that )
{
std::cout << "Derived: Derived& operator=( const Base& that )" << std::endl;
Base::operator=(that);
return *this;
}
Base& operator=( const Derived& that )
{
std::cout << "Derived: Base& operator=( const Derived& that )" << std::endl;
Base::operator=(that);
return *this;
}
};

int main()
{

Derived test1;
Derived test2(test1); // copy constructor derived(derived)
Derived test3( *static_cast<Base*>(&test1) ); // copy constructor derived(base)
test2 = test1; // assignment derived = derived
test2 = *static_cast<Base*>( &test1 ); // assignment derived = base
*static_cast<Base*>( &test1 ) = test2; // assignment base = derived
*static_cast<Base*>( &test1 ) = *static_cast<Base*>( &test2 ); // assignment base = base

return 0;
}

##### Share on other sites

If you want to cover all cases with assignment between derived-only objects via combinations of base and derived references, then I believe that is what you want to do.

As a side note, you don't need to cast via pointers, you can cast reference types also.

static_cast<Base &>( test1 ) = static_cast<Base &>( test2 );


##### Share on other sites

Thanks for the help! C++ seems to do a lot of implicit assumptions about your code...

##### Share on other sites

I was really just experimenting, as I was unclear of how overloads behaved in polymorphic structures.

If you're interested, my question was spawned by the following piece of code I wrote. I'm toying around with various pathfinding algorithms and a way to implement them on an abstract representation of data.

#include <iostream>

template <class DATA>
class NodeBase
{
protected:
NodeBase() {}
~NodeBase() {}
public:
/* omitted methods for linking/unlinking nodes with each other */
const DATA& getData() const { return m_Data; }
void setData( const DATA& data ) { m_Data = data; }
NodeBase& operator=( const NodeBase& that )
{
m_Data = that.m_Data;
return *this;
}
private:
DATA m_Data;
};

// extend functionality with coordinates
template <class COORD, class DATA>
class Node : public NodeBase<DATA>
{
public:
Node() {}
~Node() {}
const COORD& getCoordinate() const { return m_Coordinate; }
void setCoordinate( const COORD& coord ) { m_Coordinate = coord; }
private:
COORD m_Coordinate;
};

// coordinates disabled if first template parameter is specified to be "void"
template <class DATA>
class Node<void, DATA> : public NodeBase<DATA>
{
public:
Node() {}
~Node() {}
};

int main()
{

Node<void, char> test1, copy1;
Node<int, char> test2, copy2;

test1.setData( 'a' );
// test1.setCoordinate( 3 ); <-- should throw a compiler error
test2.setData( 'b' );
test2.setCoordinate( 6 );

copy1 = test1;
copy2 = test2;

std::cout << copy1.getData() << std::endl;
std::cout << copy2.getData() << std::endl;
std::cout << copy2.getCoordinate() << std::endl;

return 0;
}

The derived class doesn't require an explicit assignment operator overload because the implicit one is sufficient. I created this thread because I was wondering what would happen if the derived class "Node" suddenly did require an explicit overload.

##### Share on other sites

I created this thread because I was wondering what would happen if the derived class "Node" suddenly did require an explicit overload.

If the derived class "Node" did require an explicit overload, it would be for an assignment operator that takes an argument of the derived type, not the base type. Or perhaps I didn't fully understand your situation?

##### Share on other sites

Note that I declared Base' constructor and destructor protected, as I don't want base objects to be instantiated directly without being derived from.

As a side note, the standard way to do that is with pure virtual functions. If there's no other function that needs to be pure then make the destructor pure virtual. A class that people inherit from should generally have a virtual destructor anyway - you can run in to trouble when deleting an instance of the class if it's not.

class Base
{
public:
virtual ~Base() = 0;

virtual Base& operator=( const Base& that )
{
std::cout << "Base: Base& operator=( const Base& that )" << std::endl;
return *this;
}
};

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 16
• 11
• 9
• 24
• 51