Как я могу избежать dynamic_cast в своем коде C++?

18
задан crowne 3 November 2010 в 16:50
поделиться

10 ответов

Я предполагаю, что Автомобиль содержит указатель Механизма, и вот почему Вы находите себя downcasting.

Вынимают указатель из Вашего базового класса и заменяют его чистым виртуальным get_engine () функция. Затем Ваш FooCar и BarCar могут содержать указатели на корректный тип механизма.

(Редактирование)

, Почему это работает:

, Так как виртуальная функция Car::get_engine() возвратилась бы ссылка или указатель , C++ позволит производным классам реализовывать эту функцию с другой тип возврата, пока тип возврата только отличается, будучи большим производным типом.

Это называют ковариантные типы возврата и позволит каждому Car тип возвращать корректное Engine.

24
ответ дан 30 November 2019 в 06:22
поделиться

Всего одна вещь я хотел добавить: этот дизайн уже плохо пахнет мне из-за того, что я называю параллельные деревья .

В основном, если Вы заканчиваете с параллельными иерархиями классов (как Вы имеете с Автомобилем и Механизмом) затем Вы просто напрашиваетесь на неприятности.

я заново обдумал бы, если Механизм (и даже Автомобиль) должен иметь подклассы, или это - все просто различные экземпляры тех же соответствующих базовых классов.

10
ответ дан 30 November 2019 в 06:22
поделиться

Вы могли также templatize тип Механизма следующим образом

template<class EngineType>
class Car
{
    protected:
        EngineType* getEngine() {return pEngine;}
    private:
        EngineType* pEngine;
};

class FooCar : public Car<FooEngine>

class BarCar : public Car<BarEngine>
7
ответ дан 30 November 2019 в 06:22
поделиться

Можно сохранить 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.

2
ответ дан 30 November 2019 в 06:22
поделиться

Для FooCar было бы возможно использовать BarEngine?

В противном случае Вы могли бы хотеть использовать AbstractFactory для создания правильного автомобильного объекта с правильным механизмом.

2
ответ дан 30 November 2019 в 06:22
поделиться

Я не вижу, почему автомобиль не может состоять из механизма (если BarCar будет всегда содержать BarEngine). Механизм имеет довольно прочные отношения с автомобилем. Я предпочел бы:

class BarCar:public Car
{
   //.....
   private:
     BarEngine engine;
}
4
ответ дан 30 November 2019 в 06:22
поделиться

Я думаю, что это зависит, если Engine только конфиденциально используется Car и его дети или если Вы также хотите использовать его в других объектах.

, Если бы Engine технические возможности не характерны для Car с, я использовал бы virtual Engine* getEngine() метод вместо того, чтобы сохранить указатель в базовом классе.

, Если бы его логика характерна для Car с, я предпочел бы помещать общее Engine данные/логика в отдельном объекте (не обязательно полиморфный) и сохранил бы FooEngine и BarEngine реализация в их соответствующем Car дочерний класс.

, Когда переработка реализации более необходима, чем интерфейсное наследование, объектный состав часто предлагает большую гибкость.

1
ответ дан 30 November 2019 в 06:22
поделиться

COM Microsoft является довольно неуклюжим, но он действительно имеет новое понятие - если у Вас есть указатель на интерфейс объекта, можно запросить его, чтобы видеть, поддерживает ли он какие-либо другие интерфейсы с помощью функция QueryInterface. Идея состоит в том, чтобы повредить Ваш класс Механизма в несколько интерфейсов так, чтобы каждый мог использоваться независимо.

1
ответ дан 30 November 2019 в 06:22
поделиться

Разрешение меня не пропустило что-то, это должно быть довольно тривиально.

лучший способ сделать это должно создать чистые виртуальные функции в Механизме, которые затем требуются в производных классах, которые нужно инстанцировать.

дополнительное решение для кредита состояло бы в том, чтобы, вероятно, иметь интерфейс под названием IEngine, что Вы вместо этого passs к Вашему Автомобилю и каждой функции в IEngine чисты виртуальный. У Вас мог быть 'BaseEngine', который реализует часть функциональности, Вы хотите (т.е. 'совместно использованный') и затем имеете листовые прочь этого.

интерфейс хорош, должен Вы когда-либо иметь что-то, что Вы хотите 'посмотреть' как механизм, но вероятно не (т.е. ложные тестовые классы и такой).

0
ответ дан 30 November 2019 в 06:22
поделиться

там способ расположить вещи, таким образом, объект 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)
  {}
};
0
ответ дан 30 November 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: