2012-07-01 7 views
4

J'ai une classe abstraite Engine3D et ses structures (Vector3D, etc.) dans les fichiers d'en-tête. J'ai maintenant une implémentation pour cette classe, ConcreteEngine3D : Engine3D. En outre, j'ai d'autres classes comme ConcreteVector3D : Vector3D qui ont des membres supplémentaires et des méthodes qui seront utilisées à l'intérieur ConcreteEngine3D (pour les besoins de cet exemple, disons float length et calculateLength()).C + + changer de type dans le constructeur?

En main.cpp J'ai le code:

#include "ConcreteEngine3D.h" 
Engine3D * engine; 
... 
int main(){ 
    engine = new ConcreteEngine3D(); 
    Vector3D* vector = new Vector3D(engine, 10, 5, 2); 
} 

Je veux la vector variables soient de type ConcreteVector3D*.

je besoin de ce genre dans ConcreteEngine3D, mais main.cpp je ne sais même pas c'est ce type et ne pas utiliser les champs étendus comme length. En outre, je ne peux pas utiliser dans le fichier main.cpp spécifiquement de ConcreteEngine3D.h (seulement Engine3D.h) - c'est pour la flexibilité, en changeant la mise en œuvre doit seulement changer l'inclusion et la ligne avec new ConcreteEngine3D().

Je ne veux pas modifier ce code ci-dessus ou les en-têtes d'origine de Engine3D.

Dans le constructeur de Vector3D je mets toujours un pointeur vers Engine3D objet (et je donne ici ConcreteEngine3D type).

Peut-être que je peux faire quelque chose dans le constructeur de Vector3D pour changer le type de celui-ci?

Par exemple appel Vector3D* Engine3D::convert(Vector3D v) à l'intérieur du constructeur qui sera héritée de Engine3D dans ConcreteEngine3D (qui crée un nouvel objet ConcreteVector3D avec des champs de Vector3D et retourne).

Bien sûr que le code ne fonctionne pas:

Vector3D::Vector3D(Engine3D *engine){ 
    //how to 'return' or 'convert' the type to the one that returns engine->convert(this); 
} 

Donc, fondamentalement, je veux obtenir l'effet code ci-dessous, mais sans la ligne vector = engine->convert(vector) ou Vector3D* vector2 = new ConcreteVector3D(engine, 10, 5, 2).

#include "ConcreteEngine3D.h" 
Engine3D * engine; 
... 
int main(){ 
    engine = new ConcreteEngine3D(); 
    Vector3D* vector = new Vector3D(engine, 10, 5, 2); //produces Vector3D, not ConcreteVector3D 
    vector = engine->convert(vector); //cannot be here! but creates the right object 
    Vector3D* vector2 = new ConcreteVector3D(engine, 10, 5, 2); //also creates rights object, but cannot be here! 
} 

Aussi, je ne veux pas utiliser l'usine dans Engine3D ou ConcreteEngine3D. Je veux permettre à l'utilisateur de créer Vector3D juste comme j'ai écrit dans le premier code.

+2

Peut-être qu'il serait préférable d'écrire un mini-programme de travail démontrant le problème. Ce n'est pas très clair ce que vous essayez d'atteindre. –

+1

Et maintenant vous attribuez des pointeurs aux valeurs ('Vector3D vector = new Vector3D ...') qui ne devrait pas compiler. –

+0

Vous pouvez remplacer le 'operator new' de' Vector3D' pour qu'il alloue 'sizeof (ConcreteVector3D)'. Ensuite, dans Vector3D, créez un 'ConcreteVector3D' et' memcpy (this, ...) '. Mais ce serait horrible. Vous n'allez pas aider votre utilisateur avec de telles surprises - lisez à propos du [Principe de Least Astonishment] (http://en.wikipedia.org/wiki/Principle_of_least_astonishment). Je vous suggère de reconsidérer en utilisant une usine - avoir une méthode 'Vector3D * GetVector3D()'. Définissez-le sur un fichier cpp séparé et demandez-lui de renvoyer un pointeur vers un objet 'ConcreteVector3D'. De cette façon, vous n'aurez aucune dépendance sur 'ConcreteVector3D'. – eran

Répondre

4

Il semble que vous souhaitiez utiliser un modèle de fabrique abstrait pour instancier vos objets afin de ne pas avoir à appeler directement les constructeurs des classes concrètes. Ensuite, dans le cas où vous voudriez changer les types concrets qui implémentent vos interfaces, vous devrez seulement lier dans une implémentation différente de votre usine d'abstraction, ou sélectionner une implémentation d'usine appropriée à l'exécution. Editer: Vous ne pouvez pas utiliser l'usine ... De toute façon vous aurez besoin d'une sorte de redirection, car le constructeur retournera le type que vous instanciez.Le plus proche que vous pouvez obtenir est probablement la création d'une méthode d'usine statique "create" vers la classe Vector3D qui retourne un pointeur sur Vector3D, mais qui crée en interne une instance de classe d'implémentation concrète. Dans le cas où vous faites cela, c'est une bonne pratique de rendre le constructeur de Vector3D privé pour empêcher la création du vecteur de "fausse manière".

+1

_ "Aussi, je ne veux pas utiliser l'usine ..." _ :) –

+0

Merci, j'y pensais aussi. Malheureusement, cela me fera utiliser Vector3D v = MyFactory :: create(), au lieu du constructeur. N'y at-il aucun moyen de l'utiliser à la place? – PolGraphic

+1

@PolGraphic Si vous ne faites aucune modification au premier exemple de code, il est impossible de faire ce que vous essayez d'obtenir. Une usine est la solution appropriée. Les constructeurs ne sont pas polymorphes. Ils construiront toujours ce qu'ils vous disent qu'ils vont construire. –

0

Andrew Tomazos, sur le writting pas clair - Désolé pour cela:/

je suis d'accord avec le capitaine Giraffe, que je ne peux pas y parvenir sans les changements dans main.cpp. J'ai utilisé le modèle d'usine un peu modifié:

J'ai dû faire la fonction statique Vector3D :: create() qui appellera Engine3D :: convert() et retournera son résultat. Ainsi, le code sera:

#include "ConcreteEngine3D.h" 
Engine3D * engine; 
... 
int main(){ 
    engine = new ConcreteEngine3D(); 
    Vector3D vector = Vector3D::create(engine, 10, 5, 2); 
} 

intérieur de Vector3D :: create:

retour moteur-> convertir (nouveau Vector3D (x, y, z));

Qui va produire ConcreteVector3D (parce que le moteur est de type ConcreteEngine3D).

Modifications minimales dans main.cpp, acceptables (pas de ConcreteVector3D mentionné dans le main.cpp).

Une fois de plus, merci pour l'aide, à vous tous! :-)

+0

Bien sûr, merci. Je l'ai d'abord oublié, mais maintenant j'ai accepté la réponse de vous. – PolGraphic