Я предполагаю, что Автомобиль содержит указатель Механизма, и вот почему Вы находите себя downcasting.
Вынимают указатель из Вашего базового класса и заменяют его чистым виртуальным get_engine () функция. Затем Ваш FooCar и BarCar могут содержать указатели на корректный тип механизма.
(Редактирование)
, Почему это работает:
, Так как виртуальная функция Car::get_engine()
возвратилась бы ссылка или указатель , C++ позволит производным классам реализовывать эту функцию с другой тип возврата, пока тип возврата только отличается, будучи большим производным типом.
Это называют ковариантные типы возврата и позволит каждому Car
тип возвращать корректное Engine
.
Всего одна вещь я хотел добавить: этот дизайн уже плохо пахнет мне из-за того, что я называю параллельные деревья .
В основном, если Вы заканчиваете с параллельными иерархиями классов (как Вы имеете с Автомобилем и Механизмом) затем Вы просто напрашиваетесь на неприятности.
я заново обдумал бы, если Механизм (и даже Автомобиль) должен иметь подклассы, или это - все просто различные экземпляры тех же соответствующих базовых классов.
Вы могли также templatize тип Механизма следующим образом
template<class EngineType>
class Car
{
protected:
EngineType* getEngine() {return pEngine;}
private:
EngineType* pEngine;
};
class FooCar : public Car<FooEngine>
class BarCar : public Car<BarEngine>
Можно сохранить FooEngine в FooCar, BarEngine в BarCar
class Car {
public:
...
virtual Engine* getEngine() = 0;
// maybe add const-variant
};
class FooCar : public Car
{
FooEngine* engine;
public:
FooCar(FooEngine* e) : engine(e) {}
FooEngine* getEngine() { return engine; }
};
// BarCar similarly
, которым проблема с этим подходом состоит в том, что получение механизма является виртуальным вызовом (если бы Вы обеспокоены тем), и метод для установка механизм в Car
потребовал бы downcasting.
Для FooCar было бы возможно использовать BarEngine?
В противном случае Вы могли бы хотеть использовать AbstractFactory для создания правильного автомобильного объекта с правильным механизмом.
Я не вижу, почему автомобиль не может состоять из механизма (если BarCar будет всегда содержать BarEngine). Механизм имеет довольно прочные отношения с автомобилем. Я предпочел бы:
class BarCar:public Car
{
//.....
private:
BarEngine engine;
}
Я думаю, что это зависит, если Engine
только конфиденциально используется Car
и его дети или если Вы также хотите использовать его в других объектах.
, Если бы Engine
технические возможности не характерны для Car
с, я использовал бы virtual Engine* getEngine()
метод вместо того, чтобы сохранить указатель в базовом классе.
, Если бы его логика характерна для Car
с, я предпочел бы помещать общее Engine
данные/логика в отдельном объекте (не обязательно полиморфный) и сохранил бы FooEngine
и BarEngine
реализация в их соответствующем Car
дочерний класс.
, Когда переработка реализации более необходима, чем интерфейсное наследование, объектный состав часто предлагает большую гибкость.
COM Microsoft является довольно неуклюжим, но он действительно имеет новое понятие - если у Вас есть указатель на интерфейс объекта, можно запросить его, чтобы видеть, поддерживает ли он какие-либо другие интерфейсы с помощью функция QueryInterface. Идея состоит в том, чтобы повредить Ваш класс Механизма в несколько интерфейсов так, чтобы каждый мог использоваться независимо.
Разрешение меня не пропустило что-то, это должно быть довольно тривиально.
лучший способ сделать это должно создать чистые виртуальные функции в Механизме, которые затем требуются в производных классах, которые нужно инстанцировать.
дополнительное решение для кредита состояло бы в том, чтобы, вероятно, иметь интерфейс под названием IEngine, что Вы вместо этого passs к Вашему Автомобилю и каждой функции в IEngine чисты виртуальный. У Вас мог быть 'BaseEngine', который реализует часть функциональности, Вы хотите (т.е. 'совместно использованный') и затем имеете листовые прочь этого.
интерфейс хорош, должен Вы когда-либо иметь что-то, что Вы хотите 'посмотреть' как механизм, но вероятно не (т.е. ложные тестовые классы и такой).
там способ расположить вещи, таким образом, объект FooCar может назвать функции членства FooEngine без downcasting?
Как это:
class Car
{
Engine* m_engine;
protected:
Car(Engine* engine)
: m_engine(engine)
{}
};
class FooCar : public Car
{
FooEngine* m_fooEngine;
public:
FooCar(FooEngine* fooEngine)
: base(fooEngine)
, m_fooEngine(fooEngine)
{}
};