What are the undesirable results that the author is talking about?

This example was taken from Bruce Eckel "Thinking in C ++." Chapter 14, “Acceleration and Copy Builder” section.

#include <iostream> using namespace std; class Parent { int i; public: Parent(int ii) : i(ii) { cout << "Parent(int ii)\n"; } Parent(const Parent& b) : i(bi) { cout << "Parent(const Parent&)\n"; } Parent() : i(0) { cout << "Parent()\n"; } friend ostream& operator<<(ostream& os, const Parent& b) { return os << "Parent: " << bi << endl; } }; class Member { int i; public: Member(int ii) : i(ii) { cout << "Member(int ii)\n"; } Member(const Member& m) : i(mi) { cout << "Member(const Member&)\n"; } friend ostream& operator<<(ostream& os, const Member& m) { return os << "Member: " << mi << endl; } }; class Child : public Parent { int i; Member m; public: Child(int ii) : Parent(ii), i(ii), m(ii) { cout << "Child(int ii)\n"; } friend ostream& operator<<(ostream& os, const Child& c) { return os << (Parent&)c << cm << "Child: " << ci << endl; } }; int main() { Child c(2); cout << "calling copy-constructor: " << endl; Child c2 = c; cout << "values in c2:\n" << c2; } 

The author makes the following comment regarding this code:

"The <<operator for the Child is interesting in that it calls the <operator for the parent part inside it: by casting the Child object for the parent & (if instead you drop the object of the base class of the link, you usually get unwanted results):

 return os << (Parent&)c << cm << "Child: " << ci << endl; 

I also run the program, replacing the above statement with:

 return os << (Parent)c << cm << "Child: " << ci << endl; 

and the program works without problems, with only one expected difference. Now the Parent copy constructor is called again to copy the argument c to Parent::operator<<() .

What then are the undesirable results that the author speaks of?

+4
source share
2 answers

The problem is that when you drop what is a child difficult for the parent (and not the parent and ampere), you simply give up everything that Child a Child does.

Usually, when your classes have virtual functions (and usually have class hierarchies), you can and will (depending on the internal layout, the number of inherited classes, etc.) modify vptr, and then you go all the way down to the undefined behavior area. That is, without using references (or pointers) in class hierarchies, it effectively destroys all magic inheritance mechanisms (also called polymorphism).

This is a bit like saying dog = plane; - and using reinterpret casting (this is what C-style effectively does), you can use the compiler to warn you about it because you tell it to shut up.

+2
source

A little tangent ...

Thumb Rule . The base class should not be Copyable; instead, it should be Clonable.

Implementation : either disable Copy Constructor and Copy Assignment Operator, or just create a clean virtual method.

Relaxation: in the absence of a pure virtual method, it is easier to make the copy constructor of the base class and the assignment operator protected . Warning: this means that the child class now has the ability to refer to a copy of its parent, which can cause slicing problems.

Note. With C ++ 11, this also applies to move copies.

+1
source

Source: https://habr.com/ru/post/1395763/


All Articles