0

I am doing some experimentation with C++. I've been imporessioned by some behaviours with polymorphism. In other languages (such as c#), when I assign an object based on a derived class to an object of BaseType: this object starts working with the derived class code. Or If I have a list of BaseType objects and I put derived class based objects in it: every element works according to the specific Type. In c++ no... I obtained this behaiviour in C++ just using pointers. Is there an alternative way? Have i missed something? Here's my code example:



class GenericCar
{

public:

    virtual void PrintModelName()
    {
        std::cout << "No Model Defined \n";
    }

};

class FerrariCar : public GenericCar
{

public:
    void virtual PrintModelName() override
    {
        std::cout<<"Ferrari \n";
    }

};


int main()
{
    std::cout << "Hello World!\n";
    //instance of two Ojects: A generic Car (Base Class) and a Ferrari (inherited class)
    GenericCar Car = GenericCar();
    FerrariCar Ferrari = FerrariCar();

    Car.PrintModelName(); //base method
    Ferrari.PrintModelName(); //overrided method
    ((GenericCar)Ferrari).PrintModelName(); //base method....

    //declaring a List of Generic Cars (Base Class)
    list<GenericCar> ListOfCars; 
    ListOfCars.push_back(Car); //adding BaseClass based Object
    ListOfCars.push_back(Ferrari); //adding InheritedClass based Object
    //for each element i want to print the model name of the Car.
    for (GenericCar & CarElement: ListOfCars)
    {
       //The base method is called for each element. (The second object is Ferrari but the base method is executed)
        CarElement.PrintModelName();
    }

    //Now declaring a List of GenericCar pointers
    list<GenericCar*> ListOfCarsPointers;
    ListOfCarsPointers.push_back(&Car); //adding BaseClass based object address
    ListOfCarsPointers.push_back(&Ferrari);//adding InheritedClass based object address
    //for each element i want to print the model name of the Car.
    for (GenericCar* & CarElement : ListOfCarsPointers)
    {
        //The correct method is invoked. For the object "Ferrari" is called the overrided function instead of base class code)
        CarElement->PrintModelName();
    }

    //Now i try to assign Ferrari to Car (inherited to base)
    Car = Ferrari;//assignment
    Car.PrintModelName();//method invoke. Here, the base method is invoked. Not the overridden code...

    char c;
    std::cin >> c;

}

In C#, for example, the overridden method is called despite the explicit cast to the base class: (BaseClass)InherithedClassObject.method() invokes the overridden method and not the base one. In the iteration of the list: the overridden method is ivoked, too (Always C#).

In c++ Have I to use always pointer in order to ensure the possibility of having a polymorphic behavior? As a consequence: Have I to manage always memory allocation destroyng objects explicitally?

  • 3
    You have object-slicing without pointer. – Jarod42 Dec 22 '19 at 16:41
  • 1
    Note that c# does not have value semantics for classes and always forces you to use references to them (that is you can not *"assign an object based on a derived class to an object of BaseType"* in c#). – user7860670 Dec 22 '19 at 16:43
  • Does this answer your question? [What is object slicing?](https://stackoverflow.com/questions/274626/what-is-object-slicing) – Richard Critten Dec 22 '19 at 16:45
  • You get the polymorphic behaviour with references as well. A function can take a `GenericCar&` parameter, and you can pass a `FerrariCar` to it. – super Dec 22 '19 at 17:06
  • Ok for Object slicing: Tank you guys. Anyway, the object-slicing is not the final point i want to reach. In the two examples with the "for": I used a List without Pointers (objects references) and in the other example I used pointers to that objects. The overridden method is called just in case of pointers. This means if i want to have polymorphic behaviours: Have i use pointers? And thus, every time delete memory allocation destroyng objects explicitally? Have i to use pointers in order to guarantee possible polymorphic behaviour? – Alex Catto Dec 22 '19 at 17:29
  • @user7860670 I can certainly do it in C#. In C# the overridden method is called despite the explicit cast to the base class: (BaseClass)InherithedClassObject.method() calls overridden methot and not base. In the iteration of the list the overridden method is called, too. – Alex Catto Dec 22 '19 at 17:35
  • You are getting confused by the similar syntax. `(BaseClass)InherithedClassObject` in c++ creates a new object of base class by slicing derived object. In order to make it work "like in C#" you need to write `static_cast(InherithedClassObject)` – user7860670 Dec 22 '19 at 17:39

1 Answers1

0

When you placed Ferrari in your first list you experienced type erasure - the "GenericCar" structure was copied into the list and anything that could have identified that it was a "FerrariCar" was lost.

You need a pointer or reference to invoke polymorphic functions, have a pointer or reference gives you access to the virtual table for your object.

To have a list that could store store such car objects and be passed around to different functions you will probably want to use smart pointers so that you don't wind up with dangling pointers or memory leaks.

#include <memory>

...

list<shared_ptr<GenericCar>> cars;
cars.push_back(shared_ptr<GenericCar>(new GenericCar()));
cars.push_back(shared_ptr<GenericCar>(new FerrariCar()));
for ( shared_ptr<GenericCar> & car : cars )
    car->PrintModelName();
TheNitesWhoSay
  • 167
  • 1
  • 5
  • 1
    Please, do not link to cplusplus.com. That web site is wrong by default. Oh, and don't like to learncpp.com either. I couldn't bear reading beyond the first sentence. Which happens to be wrong. – IInspectable Dec 22 '19 at 18:03