Let's see example classes. Base class is ITransport
, transport class interface:
class ITransport {
public:
virtual void move(const Path& p) = 0;
virtual double estimateTime(const Path& path) = 0;
/*Some more methods.*/
};
Implementation:
class Transport : public ITransport {
public:
virtual void move(const Path& p) override {
currPoint_ = p.lastPoint();
}
/*Some more methods.*/
private:
Point currPoint_;
};
Let's also imagine we want to create a self moving transport class:
template <typename EnergySource>
class SelfMovingTransport : public Transport {
/*Some special methods for self moving transport.*/
};
The simplest example of self-moving transport is car:
template <typename EnergySource>
class Car : public SelfMovingTransport <EnergySource> {
public:
virtual void visitCarService() = 0;
/*Some more methods with logic for cars.*/
};
Also need to create car with internal combustion engine...
class ICECar : public Car<Petrol> {
public:
virtual void move(const Path& p) override {
Transport::move(p);
/*Some special methods for ICECar.*/
}
virtual void visitCarService() override {
/*Visit closest ICECar service.*/
}
/*Some special methods for ICECar.*/
private:
Petrol::Amount petrol_;
};
... and an electric car class.
class ElectricCar : public Car<Electriсity> {
public:
virtual void move(const Path& p) override {
Transport::move(p);
/*Some special methods for ElectricCar.*/
}
virtual void visitCarService() override {
/*Visit closest ElectricCar service.*/
}
/*Some special methods for ElectricCar.*/
private:
Electricity::Amount charge_;
};
The continuation of this logic can be, for example, adding trains class and etc.:
template <typename EnergySource>
class Train : public SelfMovingTransport<EnergySource> {
/*Not interesting.*/
};
I use c++17
compiller (MS). Not less, not more.
I want to create an array (or std::vector<Car*>
) of
pointers to cars of different types and
call some common methods for them.
For example, to have a simple way to send them all to
the service (see Car::visitCarServeice()
).
I've tried tree ideas:
- Create classes
ISelfMovingTransport
andICar
:
class ISelfMovingTransport : public virtual ITransport { /*All the same.*/ }; class ICar : public virtual ISelfMovingTransport { /*All the same.*/ };
Changed
Transprot
to:class Transport : public virtual ITransport { /* All the same. */ }
Changed
SelfMovingTransport
to:template <typename EnergySource> class SelfMovingTransport : public ISelfMovingTransport, public Transport<EnergySource> {};
Changed
Car
to:template <typename EnergySource> class Car: public ICar, public SelfMovingTransport<EnergySource> { /*All the same*/ };
In the end solution did not work, because
static_cast
can not be used to cast pointer to virtually derived class pointer (See pastebin link.). Example code can't be compiled (error: cannot convert from pointer to base class ‘ISelfMovingTransport’ to pointer to derived class ‘ElectricCar’ because the base is virtual). When I want to make actions withElectricCar
which is accessed as a pointer to aCar
, I needdynamic_cast<ElectricCar*>(carPtr)
wherecarPtr
is ofCar*
. Butdynamic_cast
is not allowed,RTTI
is turned off.
- Use
std::vector<Transport*>
and cast objects toCar
. It worked, but I did not like this solution, because it is hard to check if everything is correct. - Using
std::variant<ICECar, ElectricCar>
andstd::visit
. (std::visit([](auto& car) -> void { car.visitCarServeice(); }, carV)
). (Now implemented with this method.).
In this example (which represents a problem in a real project) I don't want to change logic (especially classes from Transport
level to Car
level).
Is there a common way to do required things without RTTI and dynamic_cast?
Is std::variant
'OK' in this situation (assuming that car classes don't
differ by size and/or memory is not important)?
Asked question, because don't know how to google that.
P.S. All examples are representation (analog, etc...) of a situation in real project. I ask you to imagine that energy type as parameter is really needed and not to think about complications (hybrid cars, etc.).
P.P.S. In the real project I need an only object of a "car" as a field of other class.