3 votes

Héritage des interfaces en diamant C++

J'ai une hiérarchie :

class ICommand
{
    public:
        virtual void start() = 0;
};

class IExtendedCommand : public ICommand
{
    public:
        virtual void doSomethingElse() = 0;
};

class ConcreteCommand : public ICommand
{
    public:
        virtual void start() {};
}    
class ExtendedConcreteCommand : public ConcreteCommand, public IExtendedCommand
{
    public:
        virtual void doSomethingElse() {};
}

Les objets ICommand et IExtendedCommand sont créés par factory.

Pour une raison quelconque, lorsque le compilateur dit que toutes les méthodes de ICommand sont pures dans ExtendedConcreteCommand...

Avez-vous une idée de la raison et de la manière de résoudre ce problème ?

PS : Oui, je suis en train de porter mon application Android vers C++/Qt (que je n'ai pas utilisé depuis 3 ans). En tout cas, j'aimerais savoir comment vous vous en sortiriez.

EDIT :

Ce que je suis en train de porter est une application de contrôle à distance pour MPC et VLC. L'idée est de créer des commandes qui peuvent être envoyées au lecteur via une usine. Factory renvoie un pointeur vers un objet qui implémente ICommand. Ainsi, en changeant les implémentations de la fabrique, différentes commandes peuvent être créées. ICommand déclare toutes les méthodes et signaux principaux. IExtendedCommand ajoute quelques informations génériques pour tous les joueurs. Donc, ce que j'aimerais faire, c'est instancier IExtendedCommand par le biais d'une fabrique, définir quelques propriétés et ensuite la lancer avec la méthode start(). J'aimerais également réutiliser la fonctionnalité de ConcreteCommand. Cela conduit au problème que j'ai décrit.

3voto

Kerrek SB Points 194696

Tu n'as pas de diamant. Tu as ceci :

   +----------------------------------- missing start() !
   V
pv start()     pv doSomethingElse()     concrete doSomethingElse()

ICommand  ---> IExtendedCommand   ---\
                                      > ExtendedConcreteCommand
ICommand  ---> ConcreteCommand    ---/

pv start()     concrete start()

Cela signifie que vous avez deux les classes de base de type ICommand et vous devez surcharger leurs deux méthodes pures. Mais seulement ConcreteCommand remplace la version "inférieure" de start et l'autre reste inchangé.

Si vous voulez un vrai diamant, vous devez faire le ICommand classe de base virtuel en utilisant l'héritage virtuel : class IExtendedCommand : virtual public ICommand et de même pour ConcreteCommand . Alternativement, vous pouvez fournir un autre surpassement pour le paramètre start en ExtendedConcreteCommand .

1voto

alestanis Points 11214

Si je comprends votre notation, ExtendedConcreteCommand est censé être une classe concrète, ce qui signifie que quelque part vous avez essayé de faire

ExtendedConcreteCommand command;

Dans le code que vous avez téléchargé, ExtendedConcreteCommand est une classe virtuelle pure car la méthode IExtendedCommand::start() est purement virtuelle.

En fait, l'héritage des diamants est une mauvaise pratique de codage et doit être évité . Si vous insistez pour faire cela, pour éviter des problèmes de compilation vous devez définir IExtendedCommand::start() . En modifiant votre classe pour

class IExtendedCommand : public ICommand
{
    public:
        virtual void doSomethingElse() = 0;
        virtual void start() {};
};

votre code se compile.

Vous pouvez également utiliser virtual l'héritage. Dans ce cas, vous aurez une seule instance de ICommand et un vrai diamant. Dans votre exemple, vous avez deux instances de ICommand : celui qui vient de IExtendedCommand et un autre venant de ConcreteCommand .

0voto

Il suffit d'hériter virtual ly de l'interface.

Cela a un coût d'exécution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X