Move assignment operator in subclass not being called / inherited - c++

I've got a simple base class and two classes that inherit from it. The problem is that the move assignment operators in each of the child classes aren't being used. Here's basically what I have:
class Parent {
public:
virtual ~Parent();
virtual Parent& operator=(Parent &&parent);
};
class Child1 : public Parent {
public:
~Child1();
Child1& operator=(Child1 &&child);
};
class Child2 : public Parent {
public:
~Child2();
Child2& operator=(Child2 &&child);
};
The implementations are littered with logs, so I know what's being called and when. Then, I run this (pseudo)code:
Parent &p {};
if (x == 1)
p = Child1 {};
else
p = Child2 {};
And I get output that looks something like this:
: Child constructor
: Parent move operator
: Child destruct
: SIGSEGV
Any idea what I'm doing wrong?

This is a classic case of slicing where you are assigning an instance of a derived type to an instance of a base type. To fix this you have to use dynamic allocation and pointers:
std::unique_ptr<Parent> p;
if(x == 1)
p = std::make_unique<Child1>();
else
p = std::make_unique<Child2>();

C++ doesn't work that way. You can't just assign a subclass object to a base class object and expect that to work; this mistake is known as "object slicing".
Also, your if-statement's condition is not comparison, it's assignment.

You have overloaded operator= for the following cases: (pseudocode)
Parent = Parent&&
Child1 = Child1&&
Child2 = Child2&&
However your code then attempts to do Parent = Child1, which wasn't one of those options. Note that the left-hand-side is the class type in which the function is defined - the return value type does not affect function overloading.
There is never implicit conversion from base class to derived class in C++, as that would be too dangerous. (You must use a cast to request that behaviour). For example, in this case it would be wrong to pass a Parent as argument to a function expecting a Child1 because that Parent is not a Child1.
However, there is implicit conversion from derived class to base class reference. So Parent = Child1 will match Parent = Parent&&. It cannot match any of the others because the left-hand-side is not implicitly converted to a derived class.
To solve this problem, your choices include:
Explicitly define Parent = Child1&& and Parent = Child2&& inside Parent (this will need forward declarations)
Have Parent = Parent&& use tag-dispatching or dynamic_cast or otherwise, to achieve the desired behaviour for all of the child classes
As mentioned by others, perhaps your design needs a re-think, as you are slicing on purpose here, but it is rare that slicing is an intended part of an object-oriented design. Possibly you intended Parent p; to actually be a reference or pointer to Parent, instead of an actual Parent.

Related

C++ copy constructor issue with parent/child classes

I've run into a problem with copy constructors...I assume there is a basic answer to this and I'm missing something obvious - maybe I'm doing something entirely wrong - but I haven't been able to figure it out.
Basically, I have a parent class and child class. The parent class contains a vector of pointers to a (different) base class object. The child class wants to instead store pointers to objects derived from that base object.
Here's a pseudocode sample, if that helps:
// Base classes
class ItemRev {
...
}
class Item {
protected:
vector<ItemRev *> m_revPtrVec;
}
Item::Item(const Item &inputItemObj)
{
// Copy contents of the input object's item rev pointer vector
vector<ItemRev *>::const_iterator vecIter = (inputItemObj.m_revPtrVec).begin();
while (vecIter != (inputItemObj.m_revPtrVec).end()) {
(this->m_revPtrVec).push_back(new ItemRev(**vecIter));
}
}
=========
// Derived classes
class JDI_ItemRev : public ItemRev {
...
}
class JDI_Item : public Item {
...
}
JDI_Item::JDI_Item(const JDI_Item &itemObj)
{
// Copy contents of the input object's item rev pointer vector
vector<ItemRev *>::const_iterator vecIter = (inputItemObj.m_revObjPtVec).begin();
// The below does not work!
while (vecIter != (inputItemObj.m_revObjPtVec).end()) {
m_revObjPtVec.push_back(new JDI_ItemRev(**vecIter));
}
}
The problem with the above is in the push_back() call in the JDI_Item copy constructor.
Given this setup, what should the child class's copy constructor look like? Do I even need a child class copy constructor? I assumed I did, because the copy constructor is creating new objects, and the parent copy constructor will create new objects that are not the type I want in the derived class (i.e., the parent object stores pointers to ItemRev objects, while the child object should store pointers to derived JDI_ItemRev objects).
As mentioned in the comments, there is probably a more succinct way to express this problem (i.e. your class structure needs some work).
However, if you want to do it this way, the easiest way to achieve it is to use a virtual clone() method in the base class of ItemRev, with overrides of it defined in derived classes.
e.g.:
class ItemRev {
virtual ItemRev* clone() const = 0;
};
class JDI_ItemRev : public ItemRev {
ItemRev* clone() const override
{
// do your actual cloning here, using the copy constructor
return new ItemRev(*this);
}
};
Now, whenever you call clone() on any class derived from ItemRev, you will be returned an ItemRev* but it will point to a fully constructed derived class. You can of course get to the derived class's interface with static_cast<> or dynamic_cast<>.
...however...
derivation often seems like an easy win but it often turns out not to be. Inheritance should only be used if the derived class really is a type of the base class. Often people select inheritance when the derived class is a lot like a base class, or shares many characteristics with a base class. This is not the time to use inheritance. It's the time to use encapsulation.
In general, inheritance is evil.
On another note, you might find this link interesting.
Presentation on inheritance as an implementation detail

C++ using this pointer in constructor initialization list [duplicate]

I have two classes with a parent-child relationship (the Parent class "has-a" Child class), and the Child class has a pointer back to the Parent. It would be nice to initialize the parent pointer upon construction of the child, as follows:
class Child;
class Parent;
class Child
{
public:
Child (Parent* parent_ptr_) : parent_ptr(parent_ptr_) {};
private:
Parent* parent_ptr;
};
class Parent
{
public:
Parent() : child(this) {};
private:
Child child;
}
Now, I know people recommend not using this in initialization list, and C++ FAQ says I'm gonna get a compiler warning (BTW, on VS2010, I don't get a warning), but I really like this better then calling some set function in Parent's constructor. My questions are:
Is the parent this pointer well-defined when the Child object is being created?
If so, why is it considered bad practice to use it as above?
Thanks,
Boaz
EDIT: Thanks Timbo, it is indeed a duplicate (huh, I even chose the same class names). So lets get some added value: how about references? Is it possible / safe to do the following? :
class Child
{
public:
Child (Parent& parnet_ptr_) : parent_ptr(parent_ptr_) {};
private:
Parent* parent_ptr;
};
class Parent
{
public:
Parent() : child(*this) {};
private:
Child child;
}
Yes. It's safe to use this pointer in initialization-list as long as it's not being used to access uninitialized members or virtual functions, directly or indirectly, as the object is not yet fully constructed. The object child can store the this pointer of Parent for later use!
The parent this pointer, in "pointer terms", is well-defined (otherwise how would the parent constructor know on which instance is it operating?), but:
the fields that are declared after the Child object aren't initialized yet;
the code in the constructor hasn't run yet;
also, the usual warnings about using virtual members from the constructor apply1.
So, the parent object in general is still in an inconsistent state; everything the child object will do on construction on the parent object, will be done on a half-constructed object, and this in general isn't a good thing (e.g. if it calls "normal" methods - that rely on the fact that the object is fully constructed - you may get in "impossible" code paths).
Still, if all the child object do with the parent pointer in its constructor is to store it to be use it later (=> when it will be actually constructed), there's nothing wrong with it.
I.e., virtual dispatch doesn't work in constructors, because the vtable hasn't been updated yet by the derived class constructor. See e.g. here.
The behaviour is well-defined so long as you don't attempt to dereference the pointer until after the Parent object has been completely constructed (as #Sergey says in a comment below, if the object being constructed is actually derived from Parent, then all of its constructors must have completed).

C++ Polymorphism: from parent class to child [duplicate]

This question already has answers here:
When should static_cast, dynamic_cast, const_cast, and reinterpret_cast be used?
(11 answers)
Closed 8 years ago.
In C++ we can convert child class pointer to parent, but is there any way to convert it back: from parent, which was obtained from child, give child class back?
I mean:
class Parent
{
...
};
class Child : public Parent
{
...
};
int main(int argc, char const *argv[])
{
Child* child = new Child();
Parent* parent = child;
Child* old_child = parent; // how to do this??
return 0;
}
Thank you for your answers.
"but is there any way to convert it back: from parent, which was obtained from child, give child class back?"
Yes, as mentioned in the other answers, there are two ways to do this.
Child * old_child = dynamic_cast<Child*>(parent);
The result of the dynamic_cast<> can be checked at runtime, thus you can determine if the parent object really represents a Child instance:
if(!old_child) {
// parent is not a Child instance
}
Also note to get this working properly, the classes in question need to have a vtable, that RTTI can actually determine their relation. The simplest form to achieve this, is giving the Parent class a virtual destructor function
class Parent {
public:
virtual ~Parent() {}
// or
// virtual ~Parent() = default;
// as suggested for latest standards
};
NOTE:
If this should apply to a general design decision, I would strongly disregard it. Use pure virtual interfaces instead, that are guaranteed to be implemented, or not.
The second way of static_cast<> can be used in environments, where you well know that parent actually is a child. The simplest form of this is the CRTP, where Parent takes the inheriting class as a template parameter
template <class Derived>
class Parent {
void someFunc() {
static_cast<Derived*>(this)->doSomething();
}
};
class Child : public Parent<Child> {
public:
void doSomething();
};
The validity of an instatiation of Parent<> and static_cast<> will be checked at compile time.
NOTE:
Another advantage is that you can use an interface for derived that makes use of
static class members of Derived
typedef's provided by Derived
... more class traits, that can be checked at compile time
You need to cast the object back to child. This is done like this:
Child * old_child = static_cast<Child*>(parent);
and
Child * old_child = dynamic_cast<Child*>(parent);
int main() {
Parent parent;
Child child;
// upcast - implicit type cast allowed
Parent *pParent = &child;
// downcast - explicit type case required
Child *pChild = (Child *) &parent;
}
You should use the dynamic_cast to do this safely:
Child *p = dynamic_cast<Child *>(pParent)
EDIT
With dynamic_cast returns a null pointer if the type is not apart of the base class, also casting to a reference throws a bad_cast exception. dynamic_cast is particularly useful if you do not know what the object type will be.
On the other hand static_cast:
Child *p = static_cast<Child *>(pParent)
This assumes that you want to reverse an explicit conversion and perform no runtime checks. This allows for flexibility but must be used with caution.
The regular downcast shown above:
Child *pChild = (Child *) &parent;
Is a C-style down cast (like a static_cast), which may also cast to a private base class (not sure about, multiple inheritance), while static_cast would cause a compile-time error. Things like numeric conversions is a good example to use this on.
Above answers are good, conceptually you can think like this,
Your Car object which is derived from Vehicle class. You can refer Car as Vehicle, and can convert to Car as it originally belonged to Car. But it will be a problem if your Vehicle object actually representing Bike and trying to convert to Car. Thats why you need safe casting.
class Vehicle
{
...
};
class Car : public Vehicle
{
...
};
class Bike : public Vehicle
{
...
};
int main(int argc, char const *argv[])
{
Vehicle* vehicle = new Car();
Car* old_car = dynamic_cast<Car *>(vehicle);
if(old_car) {
// OK Vehicle is Car, use it
}
vehicle = new Bike();
old_car = dynamic_cast<Car *>(vehicle);
if(old_car) {
// No Vehicle isn't Car, this code won't execute
}
return 0;
}

Is it safe to use the "this" pointer in an initialization list?

I have two classes with a parent-child relationship (the Parent class "has-a" Child class), and the Child class has a pointer back to the Parent. It would be nice to initialize the parent pointer upon construction of the child, as follows:
class Child;
class Parent;
class Child
{
public:
Child (Parent* parent_ptr_) : parent_ptr(parent_ptr_) {};
private:
Parent* parent_ptr;
};
class Parent
{
public:
Parent() : child(this) {};
private:
Child child;
}
Now, I know people recommend not using this in initialization list, and C++ FAQ says I'm gonna get a compiler warning (BTW, on VS2010, I don't get a warning), but I really like this better then calling some set function in Parent's constructor. My questions are:
Is the parent this pointer well-defined when the Child object is being created?
If so, why is it considered bad practice to use it as above?
Thanks,
Boaz
EDIT: Thanks Timbo, it is indeed a duplicate (huh, I even chose the same class names). So lets get some added value: how about references? Is it possible / safe to do the following? :
class Child
{
public:
Child (Parent& parnet_ptr_) : parent_ptr(parent_ptr_) {};
private:
Parent* parent_ptr;
};
class Parent
{
public:
Parent() : child(*this) {};
private:
Child child;
}
Yes. It's safe to use this pointer in initialization-list as long as it's not being used to access uninitialized members or virtual functions, directly or indirectly, as the object is not yet fully constructed. The object child can store the this pointer of Parent for later use!
The parent this pointer, in "pointer terms", is well-defined (otherwise how would the parent constructor know on which instance is it operating?), but:
the fields that are declared after the Child object aren't initialized yet;
the code in the constructor hasn't run yet;
also, the usual warnings about using virtual members from the constructor apply1.
So, the parent object in general is still in an inconsistent state; everything the child object will do on construction on the parent object, will be done on a half-constructed object, and this in general isn't a good thing (e.g. if it calls "normal" methods - that rely on the fact that the object is fully constructed - you may get in "impossible" code paths).
Still, if all the child object do with the parent pointer in its constructor is to store it to be use it later (=> when it will be actually constructed), there's nothing wrong with it.
I.e., virtual dispatch doesn't work in constructors, because the vtable hasn't been updated yet by the derived class constructor. See e.g. here.
The behaviour is well-defined so long as you don't attempt to dereference the pointer until after the Parent object has been completely constructed (as #Sergey says in a comment below, if the object being constructed is actually derived from Parent, then all of its constructors must have completed).

C++ How come I can't assign a base class to a child class?

I have code like this:
class Base
{
public:
void operator = (const Base& base_)
{
}
};
class Child : public Base
{
public:
};
void func()
{
const Base base;
Child child;
child = base;
}
My question is: since Child derives from Base (hence it should inherit Base's operator= ), how come when the statement
child = base;
is executed, I get a compiler error like this:
>.\main.cpp(78) : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const Base' (or there is no acceptable conversion)
1> .\main.cpp(69): could be 'Child &Child::operator =(const Child &)'
1> while trying to match the argument list '(Child, const Base)'
The behavior that I want is for the Child class to recognize that it's being assigned a Base class, and just "automatically" call the its parent's operator=.
Once I added this code to the Child class
void operator = (const Base& base_)
{
Base::operator=(base_);
}
then everything compiled fine. Though I dont think this would be good because if I have like 5 different classes that inherit from Base, then I have to repeat the same code in every single derived class.
NOTE: My intention for copying the Base to Child is to simply copying the members that are common to both Base and Child (which would be all the members of Base). Even after reading all of the answers below, I really don't see why C++ doesn't allow one to do this, especially if there's an explicit operator= defined in the Base class.
The standard provides the reason for your specific question in 12.8/10 "Copying class objects" (emphasis added):
Because a copy assignment operator is implicitly declared for a class if not declared by the user, a base class copy assignment operator is always hidden by the copy assignment operator of a derived class (13.5.3).
So since there's an implicitly declared operator=(const Child&) when the compiler is performing the name lookup/overload resolution for a Child::operator=(), the Base class's function signature is never even considered (it's hidden).
The code below is the behavior I wanted since the beginning, and it compiles,
class Base
{
public:
void operator = ( const Base& base_)
{
}
};
class Child : public Base
{
};
void func()
{
const Base base;
Child child;
child.Base::operator=(base);
}
I never knew that you can explicitly call something like:
child.Base::operator=(base);
Anyway, I learned a lot. Thank you for all the people that posted answers here.
You can't assign Base to Child, because Child might not be base. To use the typical animal example, what you have here is:
const Animal animal;
Dog dog;
dog = animal;
But animal might be a cat, and you certainly can't assign a cat to a dog.
That being said, you couldn't do it the other way round either:
const Dog dog;
Animal animal;
animal = dog;
A dog certainly is an animal, but you have a size issue here. animal takes up sizeof(Animal) space on the stack, but dog takes up sizeof(Dog) space, and those two amounts may be different.
When working with polymorphism in C++, you need to be working with either references or pointers. For example, the following is fine:
Dog* const dog;
Animal* animal;
animal = dog;
Here, the size of a pointer is the same regardless of what it points to, so the assignment is possible. Note that you still need to maintain the correct hierarchy conversions. Even when using a pointer, you can't assign a Base to a Child, because of the reason I explained earlier: A Base may be something entirely different from the Child.
Because a base isn't a child. Consider:
class Child : public Base
{
public:
SomeFunc();
};
void func()
{
const Base base;
Child child;
child = base;
child.SomeFunc(); // whatcha gonna call?
}
UPDATE: TO answer the question in the comment, child.SomeFunc(); is perfectly legal -- it's only a problem if th value of child isn't really a Child object. The compiler cannot allow child = base; because it would create a situation where the legal call fails.
This isn't actually an answer, but the how-to question has been answered. This is the why-not.
Classes should mean something. There should be useful things you can say about any well-formed object in the class ("class invariants"), because that way you can reason about programs on the basis of how a class works. If a class is just a collection of data members, you can't do that, and have to reason about the program on the basis of each individual data element.
The proposed assignment operator will change every data member in the base class, but won't touch the ones defined in the child class. This means one of two things.
If a Child object is well-formed after another Base object is dumped into its Base component, it means that the additional data members have no real connection with the the Base data members. In that case, Child isn't really a subtype of Base, and public inheritance is the wrong relation. Child isn't in a "is-a" relation to Base, but rather a "has-a" relation. This is usually expressed by composition (Child has a Base data member), and can also be expressed by private inheritance.
If a Child object is not well-formed after another Base object is dumped into its Base component, the proposed assignment operator is a really fast and convenient method to mess up a variable.
For an example, let's have a Mammal base class and two child classes, Cetacean and Bat. Animal has things like size and weight, and the child classes have fields related to what they eat and how they move. We assign a Cetacean to a Mammal, which is reasonable (all Cetacean-specific fields are just dropped), and now we assign that Mammal to a Bat. Suddenly, we've got an twenty-ton bat.
With a well-designed set of classes, the only way I can conceive of this assignment operator even being thought of is if the child classes have no additional data members, only additional behavior, and even then it's suspect.
Therefore, my only advice is to redo your class design. Many people, particularly those familiar with Java and other languages that tend to deep inheritance hierarchies, use inheritance far too much in C++. C++ generally works best with a large number of base classes and a relatively shallow hierarchy.
When you don't declare copy assignment explicitly, the C++ compiler will create copy assignment for you . In your case, it would be
class Child : public Base
{
public:
Child& operator=(const Child& rhs) { ... }
};
And that's why you get this compiler error. Also, it makes more sense to return a reference to itself when you provide a copy assignment because it will allow you to chain operator together.
It's not a good idea to declare a copy assignment like this.
void operator = (const Base& base_)
{
Base::operator=(base_);
}
I don't see why you only want to copy the base class portion when you do a copy assignment.
The answer is scarier than I thought.
You can do this. The standard evens has a little note about it in section 7.3.3
The main problem is that the operator= that gets defined by default in Child hides the operator= from Base so you need to import it back into the class scope using "using".
This compiles OK for me. However I find this idea very scary, and potentially fraught with undefined behaviour if stuff in Child needs to get initialised.
class Base
{
public:
void operator = (const Base& base_)
{
}
};
class Child : public Base
{
public:
using Base::operator=;
};
int main()
{
const Base base = Base();
Child child;
child = base;
}
EDIT: Made the base const again and avoid "uninitialised const" error.
The problem is that you can't assign a constant value to a non-constant variable. If you could, you could potentially modify the constant value by modifying the non-constant variable.
Is it necessary that base is const? I ask because you're really running into two problems: const correctness, and inheritence/polymorphism.
EDIT: I'm second guessing myself now regarding my first statement. Any clarification?