Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to assign base class object to a derived class object?

Assuming I have a base class A and publicly derived class B, how should I assign A object to the A base class subobject of B?

class A {...};
class B : public A {...};
A a(..);
B b(..);
static_cast<A&>(b) = a; ???

Is that doable without writing assignement operator for B? Are there any potential problems with casting b to A&? Is that standard conformant?

like image 680
andriej Avatar asked Jan 01 '11 18:01

andriej


3 Answers

Writing another answer to demonstrate why and how assign a base class object to a derived class object.

struct TimeMachineThing_Data {
..
..
};

class TimeMachineThing : private TimeMachineThing_Data
{
    static std::stack<TimeMachineThing_Data> m_stateHistory;

    void SaveState() {
        m_stateHistory.push_back( static_cast<TimeMachineThing_Data&>(*this) );
    }

    void RestoreState() {
        static_cast<TimeMachineThing_Data&>(*this) = m_stateHistory.front();
        m_stateHistory.pop_front();
    }
};

It's very useful and fully legitimate.

(Here is private inheritance, so only internally TimeMachineThing IS-A TimeMachinetime_Data)


Another one.

struct StructWithHundresField {
  string title;
  string author;
  ...

  StructWithHundresField() {
    ...
  }
};

class EasyResetClass : public StructWithHundresField {
  int not_reset_this_attriute;
public:
  void ResetToInitialStateAtAnyTime() {
    static_cast<StructWithHundresField&>(*this) = StructWithHundresField();
  }
}
like image 167
9dan Avatar answered Oct 12 '22 04:10

9dan


That's a really bad idea. A is the base, B is a derived type. By casting B to an A, you are now using A's assignment operator, which isn't going to touch any of the extra derived data. At the end of that assignment, b is still considered to be of type B, even though it now contains an A. This is the opposite of the way inheritance is meant to be used.

Changing the line to b = reinterpret_cast<B&>(a); would be even worse. Then you would be pretending that a is a B when it's not, and you be reading invalid memory.

If you truly want to do this kind of assignment, you want:

class B : public A {
    B& operator= (const A& a) { ... }
};

Then you can write a function to copy the information from the A, and somehow deal with the extra information in the derived type B, plus this would allow you to simply write:

b = a;
like image 30
Tim Avatar answered Oct 12 '22 05:10

Tim


Think for a minute about whether this is a good idea. Remember that if you have B subclassing A, then every B is an A but not every A is a B. For example, every dog is a mammal, but not every mammal is a dog. If you have a concrete B object, trying to set it to an A object isn't mathematically well-defined in most cases. Moreover, in the world of C++, because you B object is statically typed as a B, you can never assign it an object of type A in a way that will make it stop being a B. At best, you're going to overwrite just the A portion of the B object without changing any of the B-specific parts.

like image 22
templatetypedef Avatar answered Oct 12 '22 03:10

templatetypedef