1

I am implementing a class hierarchy and see calls to parent methods that I do not understand why. Using C++11 constructs and this is my first 11 project where I use some features, hence I believe this might be a benign problem.

class A{
   void update(){
       std::err << "Calling A update " << std::endl;
   } 
}

class B: public A{
   void update(){
       std::cout << "In B update! " << std::endl;
   } 
}

class C: public A{
   void update(){
       std::cout << "In C update! " << std::endl;
   } 
}

now somewhere else I have a vector containing either Bs or Cs

std::vector<A> container;
container.push_back(B());
container.push_back(C());

for(auto item: container){
    item.update();
}

prints

Calling A update
Calling A update

Why?

El Dude
  • 5,328
  • 11
  • 54
  • 101
  • 2
    Read about [object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing). Also, since `update` is not virtual, if `container` was a `vector` with appropriate other changes, A's `update` would still be called. – 1201ProgramAlarm Jan 23 '20 at 18:02
  • Follow on question: Why is `container.push_back(B());` legal? It seems like such code would never be desirable, particularly the Frankenobjects described in the linked answers. While the emergent behavior is an understandable consequence of the existing rules, adding a new rule to forbid (or at least issue a relatively low-level warning) the badness seems like a solid plan... though one that might Break Existing Code (that was already broken in a different way, but still). Ugh. – Mark Storer Jan 23 '20 at 18:43
  • @MarkStorer It is hardly never that there is need to copy the base class sub object. It is a useful feature. You can make the class abstract to make it illegal. – eerorika Jan 23 '20 at 19:12

2 Answers2

4

why is parent method called?

Because the vector contains parent objects.

It contains Bs and Cs, child objects.

It does not contain those objects. It is a vector of A objects, therefore it contains only objects of type A, and no objects of any other type. You copied the base class sub objects from the derived objects (this operation is called slicing). The copies are not base class sub objects, but separate A objects.

Furthermore, your derived classes do not override the parent class function. Only virtual functions can be overridden. Virtual dispatch can only be used by indirecting through a pointer or a reference to a base class sub object and calling a virtual function.

P.S. You also cannot call private member functions from outside the class. The example program is ill-formed.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • It contains Bs and Cs, child objects. It is defined such that it would contain anything derived from A. Hence the function pointer update of the objects should point to the respective class definition? – El Dude Jan 23 '20 at 18:03
  • 2
    @ElDude see edit. – eerorika Jan 23 '20 at 18:04
  • Maybe me working with Python is obfuscating my understanding here... Thought this is regular overloading? – El Dude Jan 23 '20 at 18:05
  • 2
    @ElDude Python is a different language. You cannot assume that inheritance, or anything else works the same in all languages. Python has no concept of value objects, and you have a vector of values here. – eerorika Jan 23 '20 at 18:08
  • Thanks. Yeah, too much time spend in Python. Have to put those python goggles off and sharpen my C++ goggles again. – El Dude Jan 23 '20 at 18:10
  • @ElDude also, you're attempting overriding. Overloading is something else. – eerorika Jan 23 '20 at 18:11
3

The vector stores instances of A, not B or C, though they are children. When you add a B or C to the container, it's downcast to an A, and you lose the information associated with B or C. Thus when you call the update() method on the items, it calls A::update for each of them.

gct
  • 14,100
  • 15
  • 68
  • 107
  • Hm, how can I create containers in C++ such that iterating through the content would call the correct method at runtime (no casts would be involved)... ? – El Dude Jan 23 '20 at 18:07
  • 2
    This is what virtual functions are for. You can make your `update` method `virtual` and then store either references or pointers of the base class type and virtual dispatch will call the correct function for you. – gct Jan 23 '20 at 18:08
  • Ok, I am missing the virtual keyword. Thanks. I thought the overloading was happening anyways without the keyword. Thanks – El Dude Jan 23 '20 at 18:09
  • 1
    Note that virtual dispatch _only_ occurs through references and pointers. If you continue to hold a type of `A` in the vector, it won't work. – gct Jan 23 '20 at 18:11