2014-03-09 5 views
0

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

enum EComponentType 
{ 
    Base = 0, 
    Material = 1 
}; 

class FComponent 
{ 
public: 
    FComponent() { m_type = EComponentType::Base; } 

    EComponentType type() { return m_type; } 

protected: 
    EComponentType m_type; 

}; 

class FMaterial : public FComponent 
{ 
public: 
    FMaterial() { m_type = EComponentType::Material; } 

    void setValue(int value) { m_value = value; } 
    int value() { return m_value; } 

private: 
    int m_value; 

}; 

int main(int argc, char *argv[]) 
{ 
    FMaterial material; 
    material.setValue(22); 

    QVector<FComponent> Components; 
    Components << material; 

    for (int i = 0; i < Components.size(); i++) 
    { 
     switch (Components[i].type()) 
     { 
     case EComponentType::Material: 

      FMaterial material = (FMaterial)(Components[i]); // --> invalid of course 

      int value = material.value(); 
      break; 
     } 
    } 

    return 0; 
} 

Update 1:

int main(int argc, char *argv[]) 
{ 
    QVector<FComponent*> Components; 

    FMaterial material; 
    material.setValue(22); 


    Components << &material; 

    for (int i = 0; i < Components.size(); i++) 
    { 
     switch (Components[i]->type()) 
     { 
     case EComponentType::Material: 

      FMaterial *m = static_cast<FMaterial*>(Components[i]); 

      int value = m->getValue(); 
      qDebug() << value; 
      break; 
     } 
    } 

    return 0; 
} 

Так это хороший выбор из-за работы или по другим причинам? Будет много классов и много типов?

+0

Если вы храните экземпляры базового класса по значению в контейнере, это никогда не будет работать, потому что вы не можете поместить производные экземпляры в контейнер по значению. Вы должны хранить указатели базового класса 'FComponent *' в контейнере в вашем случае. В этом случае вы можете создавать производные экземпляры с помощью 'new', а затем производный указатель экземпляра может быть легко введен в указатель базового класса, и его можно поместить в контейнер. Также не забудьте предоставить виртуальный деструктор в базовом классе, если вы «удаляете» экземпляры с помощью указателей базового класса. – pasztorpisti

+0

Вы должны ** никогда ** не нуждаться в проверке типа ничего, виртуальные функции там, чтобы обрабатывать различия между базой и производными автоматически. И литье, полученное на базу, нонсенс, объект производного * есть * базового класса. Как и вы, как участник [SO], все еще человек. – vonbrand

+0

@vonbrand вы можете объяснить больше или просто создать образец сообщения, например, производный класс B имеет член «int b», а производный класс C имеет член «int c». Как их использовать. Как читать их значения? –

ответ

2

Хотя я не согласен с общим дизайном здесь, как исправить свое решение:

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

EDIT: Также я только что заметил, что вы пытаетесь использовать значения, в случае классов вам нужно делать кастинг на указателях или ссылках на классы!

class FComponent 
{ 
public: 
    // Withtout this if you delete an FComponent* then the destructor of the derived class isn't called. 
    virtual ~FComponent() {} 
}; 

class FMaterial : public FComponent 
{ 

}; 

int test() 
{ 
    QVector<FComponent*> Components; 
    FMaterial* material = new FMaterial; 
    Components << material; 

    for (int i = 0; i < Components.size(); i++) 
    { 
     switch (Components[i].type()) 
     { 
     case EComponentType::Material: 
      FMaterial* material = static_cast<FMaterial*>(Components[i]); 
      int value = material->value(); 
      break; 
     } 
    } 

    // Somewhere later in your code....    
    for (int i = 0; i < Components.size(); i++) 
     delete Components[i]; 
    // TODO: remove all deleted pointers from Components 

    return 0; 
} 
+0

Ошибка: C2440: 'static_cast': не может преобразовать из 'FComponent' в 'FMaterial' Никакой конструктор не мог взять тип источника, или разрешение перегрузки конструктора было неоднозначным –

+0

Вы можете использовать указатели или ссылки, а не фактические типы классов. –

+0

@ CahitBurakKüçüksütcü в случае классов, которые вы должны выполнить при произведении указателей классов или ссылок на классы. Вы должны наложить 'Base *' на 'Derived * ', чтобы заставить его работать, если вы попытаетесь применить значение по умолчанию, то это не бросок, который вы хотите, это будет преобразование, которое хотело бы создать новый полученный путем преобразования базового класса, который не будет работать в вашем случае. – pasztorpisti

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