1

in C++;

Is there a way of calling a function from a derived class through the base class even when the function is not overridden? In other words, I'm using a base class in order to have heterogeneous containers without boost; I want to call a member function that is only specific to a derived class...

Example: (I just made this code up so there's probably a syntax error but hopefully you get the gist)

class Vehicle
{
  public:
   virtual void do_vehicle_stuff();
   // virtual void do_car_specific_stuff(); makes no sense here
}

class Car : public Vehicle
{
  public:
   void do_vehicle_stuff();
   void do_car_specific_stuff();
}

Car a,b;

list<Vehicle> vehicle_list;
vehicle_list.push_back(a);
vehicle_list.push_back(b);

vehicle_list.front().do_car_specific_stuff();

error: 'Class Vehicle' has no member named 'do_car_specific_stuff()'

2 Answers2

1

You are slicing your classes when you insert them into the list. In C++ subtype polymorphism (the kind of polymorphism you are using) only works through references or pointers but not values. When you insert your carS into the list they are converted to VehicleS.

An example:

Car c;
std::vector<Vehicle> vs;
vs.push_back(c); // slicing happens
vs.front(); // not a car anymore, but just a vehicle,
            // the Car-ness is lost through the copy operation

How do to it:

std::vector<std::unique_ptr<Vehicle>> vs;
vs.push_back(new Car());
vs.front(); // actually a Car

After you have resolved that fundamental flaw of your code, this might help you:

Vehicle* vehiclep = new Car();
if(auto carp = dynamic_cast<Car*>(vehiclep)) {
  carp->do_car_specific_stuff();
}

This is a rather costly operation and usually an indication of a design smell, so you might want to rethink what you are doing.

pmr
  • 58,701
  • 10
  • 113
  • 156
1

Here's a more appropriate design:

struct Vehicle
{
    virtual ~Vehicle() { }

    void do_vehicle_stuff()
    {
        vehicle_impl();
    }

private:
    virtual void vehicle_impl() = 0;
};

struct Car : Vehicle
{
private:
    virtual void vehicle_impl()
    {
        my_vehicle_stuff();
        my_car_specific_stuff();
    }

    void my_vehicle_stuff()      { /* what you had originally */ }
    void my_car_specific_stuff() { /* car-only stuff */ }
};

std::list<std::unique_ptr<Vehicle>> vehicles;

vehicles.emplace_back(new Car);
vehicles.emplace_back(new Motorcycle);
vehicles.emplace_back(new Carriage);
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084