2010-06-20 19 views
0

Voici l'affaire:Enregistrement d'un objet dérivé dans un autre objet comme un pointeur de base (C++)

J'ai une fenêtre de classe concrète, ce qui représente une fenêtre du système d'exploitation qui sera utilisé pour le dessin. La fenêtre peut prendre plusieurs types, tels que plein écran, fenêtre fixe, fenêtre redimensionnable, fenêtre sans bordure, etc. Ceci est implémenté en utilisant une interface IWindowType, dans laquelle les types spécifiques dérivent (les classes sont effacées pour se concentrer sur le point). D'autres implémentations peuvent être dérivées, ou la méthode de création de fenêtre sous-jacente peut être facilement modifiée. Window doit stocker son type afin qu'il puisse rappeler createWindow() s'il le faut, pour un redimensionnement de fenêtre explicite ou un changement de type complet (par exemple, en mode plein écran). Par conséquent, il stocke un pointeur IWindowType.

class Window 
{ 
public: 

private: 
    IWindowType* mType; 
}; 

Mon problème est de pouvoir stocker le type dans Windows, ce qui donne à la fenêtre la responsabilité de gérer son type. J'ai deux solutions avec ce design, dont ni l'un ni l'autre ne me plaît vraiment.

Premièrement, le client doit passer un type de fenêtre alloué dynamiquement et avoir une fenêtre avec une désallocation de même mémoire.

Window testWindow; 
testWindow.setType(new FixedWindow()); 

Cela fonctionne, mais il faut se rappeler de passer un objet alloué dynamiquement, ainsi qu'une utilisation laide de nouveau sans correspondance supprimer (pour autant que le client concerné, de toute façon). La seconde que j'ai trouvée après la recherche était l'utilisation d'une méthode clone() virtuelle, qui fonctionne aussi et qui a une syntaxe bien meilleure, puisqu'elle effectue une copie profonde de la classe dérivée, et la fenêtre prend le contrôle de cette objet copié.

IWindowType* FixedWindow::clone() const 
{ 
    return new FixedWindow(*this); 
} 

void Window::setType(const IWindowType& type) 
{ 
    if(mType) 
     delete mType; 

    mType = type.clone() 
} 

Window testWindow; 
testWindow.setType(FixedWindow()); 

Cependant, je sens la création d'une méthode clone() pour chaque classe qui nécessite cette fonctionnalité (je peux voir beaucoup de classes exigeant avec ce genre de conception) peut devenir non seulement fastidieux, mais clone() peut être utilisé hors de ce contexte, ce que je ne veux pas vraiment. Donc ma question: Y a-t-il d'autres façons de passer la propriété du type dérivé passé à setType() à Window, c'est-à-dire de donner à Window sa propre copie à gérer? Je n'ai pas besoin de garder cette conception, je suis simplement en train d'expérimenter des façons de faire, donc si une meilleure approche de conception est disponible, elle est la bienvenue.

+0

Je ne sais pas pourquoi les gens ont peur des pointeurs. J'aime mieux votre première approche, mais je ne suis pas sûr que ce soit un état mutable, alors peut-être que ça mérite d'être un param de constructeur. (Beaucoup de zélateurs anti-raw-ptr sur SO seront très en désaccord avec moi ici) Mais, vous pouvez utiliser un 'scoped_ptr' pour éviter votre propre gestion de la mémoire. – Stephen

+0

@Stephen: l'utilisation de pointeurs intelligents n'est pas une question de zèle. Ils éliminent toute ambiguïté sur la propriété des objets et garantissent la suppression des objets au bon moment, ce qui évite d'avoir à répondre à des questions comme celle-ci. –

+0

Puis-je vous demander pourquoi vous ne faites pas juste 'Window' la classe de base abstraite, et en déduisez' FixedWindow' etc. De cette façon, vous pouvez simplement faire 'Window * pTestWindow = new FixedWindow()' et ainsi de suite. –

Répondre

0

Avez-vous besoin d'accéder à ces objets de type en dehors de la classe Window? Si vous ne le faites pas, j'essaierais de cacher le fait que vous utilisez une classe pour représenter le type. Peut-être que vous pourriez faire quelque chose comme ceci:

class Window 
{ 
public: 
    enum WindowType 
    { 
     FixedWindow, 
     //more types 
    }; 

    void setType(WindowType type) 
    { 
     delete mtype; 

     //move type creation to some factory class 
     mtype = TypeFactory::createType(type); 
    } 

private: 
    IWindowType* mType; 
}; 

De cette façon, vous n'avez pas à vous soucier de la façon d'obtenir les objets de type du monde extérieur. Ils ont juste à spécifier quel type de type la fenêtre devrait être, la fenêtre décide comment ce type est représenté.