简体   繁体   中英

C++: Extend member type in derived class

I'd welcome some help with C++ inheritance to get a better grasp of the concept. Is it possible to "extend" member types when creating a derived class? I think my problem can be best demonstrated by a simple example, where I'd like to extend the class VehicleData with a new double variable:

class VehicleData {
 int yearOfManufacture;
 //Different routines, for example Serialize(), etc., warranting to create a class for just a bunch of variables
};

class BicycleData:VehicleData {
 double frameHeight; //new property that only applies to bicycles
};

//Now I create the actual classes that use the types above
class Vehicle {
 VehicleData data;
 void PrintData(); //a function that works on basic vehicle data
};

class Bicycle:Vehicle {
 BicycleData data; //should copy VehicleData when creating an instance of this class
};

The problem with this approach is that when I code the above and create a Bicycle instance, its BicycleData member hides the already existing VehicleData member.

Is there a way to extend the base class, ie simply add a new double variable (to store frame height in this example), and keep the already existing (year of manufacture) data?

Short answer; Not in the way that you're aiming for, but you can achieve something similar.

Rather than have an instance declared as you have, if you make data a pointer. You can then have BicycleData inherit VehicleData and then just replace data with the new instance in the constructor of the Bicycle.

ie

class Vehicle {
  void PrintData();
  protected:
    void replaceData(std::shared_ptr<VehicleData> d) {
      data = d;
    }

    std::shared_ptr<VehicleData> getData() {
      return data;
    }

    template<class T>
    std::shared_ptr<T> getDataAs() {
      return std::dynamic_pointer_cast<T>(data);
    }
  private:
    std::shared_ptr<VehicleData> data;
};

class Bicycle:Vehicle {
  Bicycle(){replaceData(std::make_shared<BicycleData>());}

  std::shared_ptr<BicycleData> getData() {
    return getDataAs<BicycleData>();
  }  
};

As far as I can tell, there is no clean way to do exactly what you want with inheritance alone.

You could create a template out of your base class:

template <typename Data>
class BaseVehicle
{
    Data data;
// etc.
};

class Vehicle : BaseVehicle<VehicleData>
{
// etc.
};

class Bicycle : BaseVehicle<BicycleData>
{
// etc.
};

Then the Vehicle and Bicycle classes would contain data field of VehicleData and BicycleData types respectively.

Since in your example Bicycle inherits from Vehicle privately (ie there is no support for using Bicycle polymorphically via pointer/reference to Vehicle ), this would effectively be identical to what you want to achieve.


If you do want dynamic polymorphism, you should create a separate, preferably abstract, class, defining the interface for your vehicles, eg:

class VehicleInterface
{
public:
    // Some pure virtual interface methods
    virtual void moveTo(const Vector2 position) = 0;

    virtual ~VehicleInterface() = default;
};

And then you can have your concrete vehicles inherit and implement this interface:

class Vehicle : BaseVehicle<VehicleData>, public VehicleInterface
{
public:
    virtual void moveTo(const Vector2 position) override
    {
        // implementation for Vehicle
    }
};

class Bicycle : BaseVehicle<BicycleData>, public VehicleInterface
{
public:
    virtual void moveTo(const Vector2 position) override
    {
        // implementation for Bicycle
    }
};

Then any function, which would like to work with vehicles polymorphically, can just accept a reference or a pointer to VehicleInterface :

void driveToWork(VehicleInterface* vehicle)
{
    vehicle->moveTo(getWorkPosition());
    // etc.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM