Réfléchissons à une mise en œuvre possible de CreateInfoObject
:
void InfoFactory::CreateInfoObject(AbstractInfo** info)
{
*info = new SuperInfo;
}
Maintenant, SuperInfo
et MyInfoObject
n'ont rien en droit commun?
C'est pourquoi, en général, ce qui suit est interdit:
struct Base {};
struct D1: Base {};
struct D2: Base {};
int main(int argc, char* argv[])
{
Base** base = nullptr;
D1* d = nullptr;
base = d;
}
Comme il permettrait D1
de pointer vers quelque chose sans rapport.
Il existe plusieurs solutions:
// 1. Simple
AbstractInfo* info = nullptr;
fc.CreateInfoObject(info);
// 2. Better interface
std::unique_ptr<AbstractInfo> info = fc.CreateInfoObject();
Ensuite, si vous savez avec certitude que vous avez, en fait, un MyInfoObject
vous pouvez utiliser:
MyInfoObject* myInfo = static_cast<MyInfoObject*>(info);
ou si vous n'êtes pas sûr:
MyInfoObject* myInfo = dynamic_cast<MyInfoObject*>(info);
qui va définir myInfo
à nullptr
si jamais le info
n'a pas indiqué une instance de MyInfoObject
(ou dérivé).
Gardez à l'esprit cependant, que votre interface est vraiment horrible. C'est très C-ish et on ne sait pas si la mémoire est effectivement allouée ou non ... et qui est responsable de la gérer si c'est le cas.
EDIT:
En bon style C++, nous utilisons à la fois RAII indiquent la propriété et assurer le nettoyage nécessaire. RAII est bien connu mais pas très indicatif, je préfère moi-même la nouvelle SBRM (Scope Bound Resources Management).
L'idée est qu'au lieu d'utiliser un pointeur nu, qui ne donne pas d'indication sur la propriété (c.-à-vous devez appeler supprimer sur elle?) Vous devez utiliser un pointeur intelligent , comme par exemple unique_ptr
.
Vous pouvez également utiliser le paramètre return de la méthode, pour éviter un processus d'initialisation en deux étapes (créez d'abord le pointeur, puis faites-le pointer vers un objet). Voici un exemple concis:
typedef std::unique_ptr<AbstractInfo> AbstractInfoPtr;
// Note: if you know it returns a MyInfoObject
// you might as well return std::unique_ptr<MyInfoObject>
AbstractInfoPtr InfoFactory::CreateInfoObject()
{
return AbstractInfoPtr(new MyInfoObject());
}
// Usage:
int main(int argc, char* argv[])
{
InfoFactory factory;
AbstractInfoPtr info = factory.CreateInfoObject();
// do something
} // info goes out of scope, calling `delete` on its pointee
Ici, il n'y a aucune ambiguïté quant à la propriété.
, notez aussi que vous comprenez mieux votre question ici:
std::unique_ptr<MyInfoObject> info = factory.CreateInfoObject();
ne compilerait pas parce que vous ne pouvez pas convertir un AbstractInfo*
à un MyInfoObject*
sans utiliser static_cast
ou dynamic_cast
.
L'édition parle de votre commentaire! –
@Tony: J'ai modifié ma réponse avec une proposition d'interface alternative. –
Merci beaucoup pour l'explication. Est-ce que je peux maintenant faire une distribution descendante de mon AbstractInfoPtr récupéré à un objet dérivé ?? est-ce une bonne idée? –