C ++ fundição programaticamente: pode ser feito?
Pergunta
Digamos que eu tenho um Base de Dados classe e vários Derivados classes. Existe alguma maneira de converter um objeto para uma das classes derivadas, sem a necessidade de escrever algo como isto:
string typename = typeid(*object).name();
if(typename == "Derived1") {
Derived1 *d1 = static_cast< Derived1*>(object);
}
else if(typename == "Derived2") {
Derived2 *d2 = static_cast < Derived2*>(object);
}
...
else {
...
}
Solução
Não faça isso.
Leia-se sobre polimorfismo. Quase todas as situações "elenco dinâmico" é um exemplo de polimorfismo lutando para ser implementado.
decisão Tudo o que você está fazendo no elenco dinâmica já foi feita. Apenas delegar o trabalho real para as subclasses.
Você deixou de fora a parte mais importante do seu exemplo. O, o trabalho polimórfica útil.
string typename = typeid(*object).name();
if(typename == "Derived1") {
Derived1 *d1 = static_cast< Derived1*>(object);
d1->doSomethingUseful();
}
else if(typename == "Derived2") {
Derived2 *d2 = static_cast < Derived2*>(object);
d2->doSomethingUseful();
}
...
else {
...
}
Se a cada implementos subclasse doSomethingUseful, tudo isso é muito mais simples. E polimórfico.
object->doSomethingUseful();
Outras dicas
Você pode usar dynamic_cast
e teste para NULL, mas eu fortemente considerar refatoração do código em vez.
Se você precisa subclasse específica de manipulação, Template Method pode ser útil, mas sem saber o que você está tentando alcançar, é apenas uma vaga suposição.
Derived1* d1 = dynamic_cast< Derived1* >(object);
if (d1 == NULL)
{
Derived2* d2 = dynamic_cast< Derived2* >(object);
//etc
}
Eu tenho os seguintes métodos no meu tipo de ponteiro inteligente, simulando C # 'é' e 'como':
template< class Y > bool is() const throw()
{return !null() && dynamic_cast< Y* >(ptr) != NULL;}
template< class Y > Y* as() const throw()
{return null() ? NULL : dynamic_cast< Y* >(ptr);}
Você pode fazer isso usando dynamic_cast
, por exemplo:
if ( Derived1* d1 = dynamic_cast<Derived1*>(object) ) {
// object points to a Derived1
d1->foo();
}
else if ( Derived2* d2 = dynamic_cast<Derived2*>(object) ) {
// object points to a Derived2
d2->bar();
}
else {
// etc.
}
Mas, como já foi dito, o código como este pode indicar um design ruim, e geralmente você deve usar funções virtuais para implementar o comportamento polimórfico.
Normalmente, este é um sinal de uma má concepção. Por que você tem que fazer isso? Pode ser possível para redesenhar para que isso não é necessário.
O que você está tentando realizar, exatamente? Na minha experiência, coisas como esta são um sinal de design ruim. Re-avaliar a sua hierarquia de classes, porque o objetivo do projeto orientado a objetos é fazer as coisas como este desnecessário.
Seu exemplo não porta, porque o formato exato do nome () é não especificado. Você poderia tentar uma sucessão de dynamic_cast
s. Dynamic_cast
retorna um ponteiro nulo se você converter para o tipo errado. No entanto, se você está fazendo um typeswitch como este, há algo de errado com seu projeto.
Eu acho que dynamic_cast é o caminho a percorrer, mas eu particularmente não acho que este é um projeto ruim para todas as condições possíveis porque objeto a ser fundidas pode ser algo fornecido por algum módulo de terceiros. Vamos objeto digamos foi criado por um plug-in que o autor do aplicativo não tem conhecimento de. E que plug-in particular pode criar Derived1 (sendo a versão antiga) tipo de objeto ou Derived2 (sendo a nova versão) tipo de objeto. Talvez o plug-in interface não foi projetada para fazer coisas versão específica, ele simplesmente cria o objeto para que o aplicativo deve fazer esse tipo de verificação para garantir adequada fundição / execução. Depois disso, podemos seguramente chamar object.doSomethingUsefulThatDoesNotExistInDerived1 ();