2015-01-15 4 views
4

У меня возникла следующая проблема.виртуальные методы C++

я реализую родительский класс - Vehicle, он имеет некоторые производные классы, один из них - FastVehicle.

В программе мне нужно хранить указатели Vector of Vehicle *. указатели могут указывать на объекты транспортного средства или объекты FastVehicle.

1) Я хочу, чтобы иметь возможность называть метод print() для каждого объекта в векторе. Проблема заключается в том, что в случае FastVehicle я также хочу Tranfer параметр функции, мне нужно вызвать функцию с подписью:

void print(int a) 

Я знаю немного о механизме виртуальной функции, но по Насколько мне известно, это работает, только если обе функции имеют одну и ту же подпись.

Я хотел бы услышать предложения, касающиеся того, как это работает.

2) Кроме того, в производном классе FastVehicle имеет уникальную функцию, которую он не разделяет с родительским классом Vehicle. Выполняет задачу, которая должна выполняться только для FastVehicle объектов. Каков самый чистый способ достичь этого? я подумал, что для реализации «пустой» виртуальной функции в родительском классе автомобиля и реализовать «реальную» задачу внутри наиважнейшей методы FastVehicle

Может быть кто-то может предложить лучшее решение.

благодарит

+0

Либо реализовать общий интерфейс, либо использовать dynamic_cast. –

+1

'dynamic_cast' - это ответ, если вы действительно хотите, чтобы производные классы имели несовместимые интерфейсы. Определение общего интерфейса было бы намного чище, если можно. –

+1

Необходимость использования 'dynamic_cast' часто является признаком того, что вы недостаточно продумали все. – OMGtechy

ответ

1

Вы всегда можете использовать dynamic_cast, чтобы бросить Автомобиль в FastVehicle. Он возвращает NULL, если автомобиль не является FastVehicle. Это зависит от вашей ситуации использования, если вы действительно должны это делать.

for(Vehicle* vehicle : vehicleVector) 
{ 
    FastVehicle* fastVehicle = dynamic_cast<FastVehicle*>(vehicle); 

    if(fastVehicle) 
    { 
     fastVehicle->print(1337); 
     fastVehicle->somethingElse(); 
    } 
    else 
    { 
     vehicle->print(); 
    } 
} 

Полный пример можно найти здесь: https://ideone.com/69n6Jb

+0

Благодарим вас за ответ. Нужно ли родительскому классу иметь хотя бы одну виртуальную функцию для выполнения dynamic_cast? –

+1

@Day_Dreamer Да, это так. – Scintillo

+0

Не думайте, что это сработает. Я думаю, что dynamic_cast бросает в сторону (между братьями и сестрами) просто отлично, поэтому вы никогда не столкнетесь с другим. – ventsyv

0

Может быть, вы могли бы реорганизовать с абстрактным vehicleI:

struct vehicleI { 
    .... 
    virtual void print(int) = 0; 
} 

, а затем ваш vehicle:

struct vehicle : vehicleI { 
    .... 
    void print(int i = 0); 
} 

и ваш fastVehicle как:

struct fastvehicle: vehicleI { 
    .... 
    void print(int); 
} 
+1

Обратите внимание, что параметр 'i = 0' по умолчанию не будет использоваться, если вы вызываете печать на указателе' vehicleI', поскольку параметр по умолчанию основан на статическом типе. Лично я бы полностью избегал параметра по умолчанию, чтобы избежать путаницы. –

+0

@ChrisDrew хорошая точка, должна быть как 'printf' и принимать переменное количество параметров. Или быть потоком какого-то ... –

1

прагматические решения:

  1. Пропустите параметр int a к виртуальному print метод, но игнорировать его в Vehicle и использовать его только в FastVehicle

  2. Как вы предлагаете, просто добавьте «пустая» виртуальная функция для базового класса, которая является no-op в Vehicle и реализована только в FastVehicle

например:

struct Vehicle { 
    virtual ~Vehicle(){} 
    virtual void print(int /*a*/) const { std::cout << "Vehicle print\n"; } 
    virtual void somethingElse() { /* no-op */ } 
}; 

struct FastVehicle : Vehicle { 
    void print(int a) const override {std::cout << "FastVehicle print " << a << "\n";} 
    void somethingElse() override { std::cout << "Something else!\n"; } 
}; 

for (auto vehicle : vehicles) { 
    vehicle->print(512); 
    vehicle->somethingElse(); 
} 

Live demo

0

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

У вас есть два решения:

параметров по умолчанию

struct Vehicle 
{ 
    virtual void print(int a=0) {}; 
}; 

struct FastVehicle : public Vehicle 
{ 
    void print(int a=0) override {}; 
}; 

теперь вы можете позвонить и с или без параметра.

Второй вариант:

struct Vehicle 
{ 
    virtual void print() {}; 
}; 

struct FastVehicle : public Vehicle 
{ 
    void print() override {}; 
    void setA(int a) { _a = a; } 
    _a{}; 
}; 

Теперь вы можете установить «а» переменную через другой метод, но не тогда, когда вы получаете доступ к объекту через интерфейс транспортного средства.

1

Скорее всего, вам нужно переосмыслить, почему вам нужен параметр для FastVehicle, но не для чего-либо другого типа транспортного средства. Это для меня показатель плохого дизайна.

Просто объявите print (int) в базовом классе, переопределите его, но в классах, где вам не нужен int, просто игнорируйте его.

Смежные вопросы