2013-08-12 2 views
0

У меня возникла проблема с литьем экземпляра объекта значением его члена. Тестовый пример:Значение объекта

class base { 
    public: 
     virtual int type() const = 0; 
}; 
class derived : public base { 
    public: 
     virtual int type() const { return 1; } 
     virtual void derivedspecific() {} 
}; 

int main() { 
    base* test = new derived; 
    (test->type()==1?((derived*)test):NULL)->derivedspecific(); 
} 

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

+4

Это звучит как НЕПРАВИЛЬНОЕ решение какой-либо проблемы ... И вы должны использовать 'dynamic_cast', но в целом вы делаете что-то не так, когда используете наследование, а затем проверяете, что это за тип [если это не случай, если' if (object-> classVersion()> 1) ... 'или что-то подобное для сохранения обратной совместимости в двоичной совместимой системе]. –

+1

'(test-> type() == 1? ((Производный *) тест): NULL) -> производный специфический();' может стать 'NULL-> производным специфическим()'. Не используйте тернарный оператор для этого. – nouney

+0

Тогда, пожалуйста, дайте мне просто идею, как мгновенно менять ценность члена? Макро решение приемлемо для меня. Спасибо :) –

ответ

2

Прежде всего, ваш derivedspecific не нужно быть Virual, как это выглядит, как вы не называть его указателем на базовый класс. Я предполагаю, что имя будет всегда отличаться в производных классах. В противном случае, если derivedspecific всегда то же самое имя и подпись, вы на самом деле не нужно type():

class base 
{ 
public: 
    virtual int doWork() const = 0; 
}; 
class derived : public base 
{ 
public: 
    virtual void doWork() { /* do your work here*/ } 
}; 
int main() 
{ 
    base* test = new derived; 
    test->doWork(); 
} 
+0

Как-то мне нужно, чтобы производные классы были разными. Некоторые будут иметь нулевые конкретные методы, а некоторые - десятки. Итак, в основном я должен объявить все производные конкретные методы в базовом классе? –

+1

В этом случае для чего вам нужен общий базовый класс? Это может быть признаком того, что наследование не очень подходит. Можете ли вы сказать, что производные объекты ** являются ** базовым классом? Как и в классическом примере, «автобус - это транспортное средство», поэтому в теории вы можете получить автобус от транспортного средства. Если вы не можете сказать, что ваш 'output' является' base', попробуйте использовать состав и/или агрегацию. – Karadur

+0

Я работаю над представлением AST. АСТ содержит утверждения. Каждое утверждение имеет разные вещи. Теперь вы теперь почему. Хорошо, я мог бы сделать так, чтобы каждый оператор был типом Statement, но это было бы очень запутанным для сотен операторов операторов и выражений и т. Д. –

1
  1. NULL->derivedspecific() не компилировать
  2. ((derived*)NULL)->derivedspecific() не определено поведение (ошибка сегментации на большинстве платформ

есть механизм, который специально разработан для поддержки такого поведения, т.е. dynamic_cast, который идет как :

#include <typeinfo> 

class base 
{ 
    public: 
     virtual ~base(){}; 
}; 
class derived1 : public base 
{ 
    public: 
     void derived1specific() const {} 
}; 
class derived2 : public base 
{ 
    public: 
     void derived2specific() const {} 
}; 
int main() 
{ 
    // use pointers 
    base* test = new derived1; 
    derived2* d2 = dynamic_cast<derived2*>(test); 
    if(d2) 
     d2->derived2specific(); 
    derived1* d1 = dynamic_cast<derived1*>(test); 
    if(d1) 
     d1->derived1specific(); 

    // or simply 
    if(derived1* d1 = dynamic_cast<derived1*>(test)) 
     d1->derived1specific(); 
    else if(derived2* d2 = dynamic_cast<derived2*>(test)) 
     d2->derived2specific(); 


    // use references 
    const base& testr = derived1(); 
    try{ 
     const derived1& d1 = dynamic_cast<const derived1&>(testr); 
     d1.derived1specific(); 
    } 
    catch(std::bad_cast&){} 
    try{ 
     const derived2& d2 = dynamic_cast<const derived2&>(testr); 
     d2.derived2specific(); 
    } 
    catch(std::bad_cast&){} 
} 

Что вы хотели бы сделать, что бы я не рекомендовал вам, это примерно так:

auto doNothing = [](){return;}; 
(test->type()==1?(((derived1*)test)->derived1specific()):doNothing()); 

Вы можете попробовать весь код here.

Что касается Вашего комментария: Вы можете заменить макрос с свободной функцией (что рекомендуется в любом случае)

void derived1specific(base* b){ 
    if(derived1* d1 = dynamic_cast<derived1*>(b)) 
     d1->derived1specific(); 
} 

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

derived1specific(test); 
+0

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

+0

Вам не нужно будет писать его каждый раз, вы можете использовать бесплатную функцию, в значительной степени, как вы бы использовали макрос. Использование функции в любом случае лучше! –

0

Для этого используйте переключатель:

Base * test = //something returning a Base * 
switch(test) 
{ 
    case 0 : 
     static_cast<Derived0*>(test)/*[...]*/; 
     break; 
    case 1 : 
     static_cast<Derived1*>(test)/*[...]*/; 
     break; 
//... 
} 

Если Существует только возвращение которым один класс тот же тип(), поэтому вы можете использовать static_cast, потому что вы уверены.

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