2016-12-19 9 views
2

Я прочитал некоторые ответы в What is the proper use case for dynamic_cast.Рекомендуется ли использовать динамический кастинг для предоставления входных данных для виртуальной функции производного класса?

линия, которая лучше всего соответствует моей ситуации здесь

#include<iostream> 

class Shape 
{ 
    public: 
     virtual void draw()=0; 
     virtual ~Shape(){}; 
}; 

class Rectangle : public Shape 
{ 
    public: 
     int length; 
     int breath; 

     void draw() 
     { 
     std::cout<<"RECTANGE"<<std::endl; 
     } 

}; 


class Circle : public Shape 
{ 
    public: 
     int diameter; 

     void draw() 
     { 
     std::cout<<"CIRCLE"<<std::endl; 
     } 

}; 


/*Abstract Factory*/ 

Shape* getShapeObj(int type) 
{ 
    switch(type) 
    { 
     case 1: 
     return new Rectangle; 

     case 2: 
     return new Circle; 

     /* many types will be added here in future. */ 
    } 

    return NULL; 
}; 

void drawShapes(Shape *p_shape[],int len) 
{ 
    for(int i=0;i<len;i++) 
     p_shape[i]->draw(); 
} 

int main() 
{ 
    Shape *l_shape[2]; 
    l_shape[0]=getShapeObj(1); 
    l_shape[1]=getShapeObj(2); 
    Rectangle *l_rec=dynamic_cast<Rectangle*>(l_shape[0]); 

    if(l_rec) 
    { 
     l_rec->length=10; 
     l_rec->breath=20; 
    } 

    Circle *l_circle=dynamic_cast<Circle*>(l_shape[1]); 

    if(l_circle) 
     l_circle->diameter=25; 

    drawShapes(l_shape,2); 

} 

По сути, виртуальные функции работают только в некоторых случаях, не все из них.

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

+1

* ", чтобы передать вход для виртуальной функции, и входы будут различаться от типа к типу" * - Я не вижу места в вашем коде, где вы используете виртуальные функции с некоторыми входами ... Не могли бы вы уточнить? Вы не можете переопределить виртуальную функцию и изменить ее параметры ... – Holt

+0

Что делает вышеприведенный код таким, что 'Rectangle * l_rec = new Rectangle (10, 20);' не достигает? (Или даже лучше 'auto l_rec = std :: make_unique (10,20);'). Я понимаю, что это упрощенный пример, но я не вижу, как будет выглядеть сложный пример. –

+0

@Holt обновил код с помощью разработанного примера –

ответ

2

Решение - идеальная пересылка функциональных параметров, введенных в C++ 11.

template<typename ...CtorArgs> 
Shape* getShapeObj(int type, CtorArgs&& ctor_args...) 
{ 
    switch(type) 
    { 
     case 1: 
     return new Rectangle(std::forward<CtorArgs>(ctor_args)...); 
    // many types will be added here in future. 
    } 

    return NULL; 
} 

Очевидно, что делает функцию шаблона, побеждает цель сокрытия иерархии (а также заставляя довольно жесткие требования в отношении числа параметров к конструкторам). Но если база содержит карту функций, выполняющих конструкцию, которые каждый производный класс обновляет с помощью указателя на функцию, которая его создает, вы все равно можете скрывать информацию.


Я недавно написал answer о хранении типа стерта указателей на функции в карте, некоторые статические проверки типов направлен во время выполнения.

+2

Это будет работать, только если все подклассы имеют одинаковые параметры конструктора, так как все тело функции должно быть хорошо сформировано. – Holt

+1

@ Хольт - Да. Торможение в отдельности для размещения различных параметров c'tor потребует уровня косвенности, скажем, посредством отправки тега. Но дело в том, что есть способы избежать «dynamic_cast». – StoryTeller

0

В этом конкретном случае, похоже, ваша функция main берет на себя слишком большую ответственность. Что делать, если у вас есть Circle, Hexagon, MyFancyFigure? Все они должны быть инициализированы в main в разных ветках?

Было бы гораздо лучше перенести эту логику инициализации на отдельную виртуальную функцию init в ваши классы (или даже на конструктор). Код будет выглядеть следующим образом:

class Shape 
{ 
    public: 
     virtual void draw()=0; 
     virtual void init()=0; 
     virtual ~Shape(){}; 
}; 

class Rectangle : public Shape 
{ 
    public: 
     int length; 
     int breath; 

     void draw() 
     { 
     //Draw Rectangle 
     } 

     void init() 
     { 
     length = 10; 
     breath = 20; 
     } 
}; 

int main() 
{ 
    Shape *l_shape=getShapeObj(1); 
    // Calls different code of "init" method depending on the actual object type 
    l_shape->init(); 
    l_shape->draw(); 
    delete l_shape; 
} 

Кроме того, обратите внимание, что эта инициализация логика может быть место в каком-то другом месте, как конструктор класса или заводским способом. Но main - это, безусловно, неправильное место.

+0

@alexykuzmin Мои данные зависят от типа. Сказать, что вы жестко закодировали ввод в init. –

+0

@VinothKumar Если это зависит от типа, у вас, вероятно, есть более одного, если в функции 'main'. Этот код будет выглядеть намного лучше при распределении между несколькими 'init' функциями производных классов. Надеюсь, я правильно тебя понял. – alexeykuzmin0

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

  • Нет связанных вопросов^_^