Question

J'ai la hiérarchie de classe suivante en C ++:

class Base {
    virtual void apply() = 0;
};

class Derived : public Base {
    virtual void apply() {
        // implementation here that uses derived_specialty
    }

    virtual void derived_specialty() = 0;
};


class Implementation : public Derived {   
    virtual void derived_specialty() {
        // implementation
    }
};

Je voudrais garantir que les classes au niveau de mise en œuvre ne fournissent pas leur propre mise en œuvre d'appliquer, et qu'ils ne derived_specialty mettre en œuvre. Est-il possible de garantir que les classes héritant de dérivées n'exécuterons pas appliquer, de sorte que la mise en œuvre Derived :: appliquer est utilisé? Je crois comprendre que dans C ++, une méthode virtuelle fait dans la classe de base est virtuel tout le long de la hiérarchie d'héritage, mais s'il y a des astuces en C ++ pour accomplir, je serais intéressé à entendre parler.

Je suis toujours surpris par les choses qui sont permises par C ++, donc je pensais que ça valait la peine de demander. :)

Était-ce utile?

La solution

Vous pouvez le faire de sorte par la composition:

class Base {
    virtual void apply();
};

class Derived : public Base {

    class IImplementation {
        virtual void derived_specialty() = 0;
    };

    IImplementation& m_implementation;

    Derived(IImplementation& implementation)
        : m_implementation(implementation)
    {}

    virtual void apply() {
        // implementation here that uses m_implementation.derived_specialty
    }

};


class Implementation : Derived::IImplementation {   
    virtual void derived_specialty() {
        // implementation
    }
};

D'autres classes peuvent encore sous-classe dérivée et remplacer la méthode appliquer, mais votre classe d'implémentation n'est plus une de ces classes.

Autres conseils

Vous pouvez faire la mise en œuvre d'une classe déléguée plutôt qu'une spécialisation dérivée

class Derived : public Base
{
    Derived()

    void apply() 
    {
        //whatever, delegate to impl class instance
        impl->apply_specialization();
    }


    Impl* impl;
};

class Impl : public WhateverImplInterface
{
      void apply_specialization(){}
};

Ensuite, la mise en œuvre n'a pas accès à la fonction appliquer et est séparée de la hiérarchie. La classe dérivée est alors paramétrés par une instance de classe Impl.

Faire la restriction claire dans votre documentation.

« Je voudrais garantir que les classes au niveau de mise en œuvre ne fournissent pas leur propre mise en œuvre d'appliquer. »

Vous ne pouvez pas.

Aucun des exemples que j'ai vu empêcher jusqu'à présent l'une des classes dérivées de la définition de leur propre fonction appliquent. Ils ont tous fournissent des méthodes pour modéliser la relation entre appliquer et derived_specialty, ce qui suggère aux utilisateurs qu'ils ne devrait pas override appliquer. Vous pouvez obtenir le même dans une ligne de documentation, cependant.

Qu'est-ce que vous cherchez est la déclaration finale Java qui n'existe pas en C ++, droit?

Vous pouvez faire de base :: appliquer non virtuel et utiliser le modèle de la méthode de modèle au sein de la base aussi.

Cet article explique les avantages de cette pratique:
http://www.gotw.ca/publications/mill18.htm

Vous pouvez mettre une affirmation dans le destructor pour vous assurer que Appliquer n'a pas été surchargée:

class Base {
    virtual void apply() = 0;
};

class Derived : public Base {
    virtual void apply() {
        // implementation here that uses derived_specialty
    }
    virtual ~Derived() {
        assert(this->apply == Derived::apply);
    }
    virtual void derived_specialty() = 0;
};


class Implementation : public Derived {   
    virtual void derived_specialty() {
        // implementation
    }
};

L'idée est ici que this-> Apply obtenir l'adresse de la méthode de la table virtuelle, tandis que Derived :: l'appliquer se résorbe en compilation. Si elles sont égales, appliquer n'a pas été à nouveau la classe de substitution dans la mise en œuvre. Cette approche a aussi l'avantage qu'il impose aucune pénalité de performance dans la construction de libération, où assert () macros sont (doivent être) dépouillés du code généré.

Essayez d'utiliser la méthode de configuration de modèle

Wikipédia a un exemple de C ++.

Il ne change pas l'encapsulation, mais il améliore la conception de sorte que vous n'avez pas besoin.

Il y a toujours des modificateurs d'accès:

 class base {
      protected: virtual void real_apply() = 0;
 };
 class derived : public base {
      void real_apply();
 public:
      apply() { real_apply(); }
 };
 class other : public derived {
      void func() {
          apply();      // this is ok
          real_apply(); // this is a compile time error
      }
 };
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top