69 votes

Empêcher l'héritage des classes en C++

Récemment, un de mes amis m'a demandé comment empêcher l'héritage des classes en C++. Il voulait que la compilation échoue.

J'y ai réfléchi et j'ai trouvé 3 réponses. Je ne suis pas sûr de savoir laquelle est la meilleure.

1) Constructeur(s) privé(s)

class CBase
{

public:

 static CBase* CreateInstance() 
 { 
  CBase* b1 = new CBase();
  return b1;
 }

private:

 CBase() { }
 CBase(CBase3) { }
 CBase& operator=(CBase&) { }

};

2) Utilisation de CSealed classe de base, ctor privé & héritage virtuel

class CSealed
{

private:

 CSealed() {
 }

 friend class CBase;
};

class CBase : virtual CSealed
{

public:

 CBase() {
 }

};

3) Utilisation d'un CSealed classe de base, ctor protégé & héritage virtuel

class CSealed
{

protected:

 CSealed() {
 }

};

class CBase : virtual CSealed
{

public:

 CBase() {
 }

};

Toutes les méthodes ci-dessus permettent de s'assurer que CBase ne peut plus être héritée. Ma question est la suivante :

  1. Quelle est la meilleure méthode ? Existe-t-il d'autres méthodes ?

  2. Les méthodes 2 et 3 ne fonctionneront pas si le CSealed est héritée virutalement. Comment cela se fait-il ? Est-ce que cela a quelque chose à voir avec le ptr vdisp ?

PS :

Le programme ci-dessus a été compilé dans le compilateur MS C++ (Visual Studio). référence : http://www.codeguru.com/forum/archive/index.php/t-321146.html

0voto

T.E.D. Points 26829

Si vous le pouvez, j'opterais pour la première option (constructeur privé). La raison est que presque tous les programmeurs C++ expérimentés verront cela d'un seul coup d'oeil et seront capables de reconnaître que vous essayez d'empêcher la sous-classification.

Il existe peut-être d'autres méthodes plus délicates pour empêcher le sous-classement, mais dans ce cas, le plus simple est le mieux.

0voto

Alexis Paques Points 1022

À partir de C++11, il existe une solution propre que je suis surpris de ne pas voir ici. Nous pouvons rendre la classe finale en empêchant tout héritage ultérieur.

class Foo final {};

class Bar: public Foo {}; // Fails to compile as Foo is marked as final

-1voto

Sergey Teplyakov Points 6556

Une solution de plus :

template < class T >
class SealedBase
{
protected:
    SealedBase()
    {
    }
};

#define Sealed(_CLASS_NAME_) private virtual SealedBase<_CLASS_NAME_>

#include "Sealed.h"

class SomeClass : Sealed(Penguin)
{
};

-1voto

Vijay Points 1
class myclass;

    class my_lock {
        friend class myclass;
    private:
        my_lock() {}
        my_lock(const my_lock&) {}
    };

    class myclass : public virtual my_lock {
        // ...
    public:
        myclass();
        myclass(char*);
        // ...
    };

    myclass m;

    class Der : public myclass { };

    Der dd;  // error Der::dd() cannot access
            // my_lock::my_lock(): private  member

Je l'ai trouvé ici pour lui donner du crédit. Je le poste ici pour que d'autres personnes puissent y accéder facilement. http://www.devx.com/tips/Tip/38482

-1voto

Blazej Czapp Points 552

Pour approfondir La réponse de Francis : si la classe Bottom dérive de la classe Middle qui hérite virtuellement de la classe Top c'est la classe la plus dérivée ( Bottom ) qui est responsable de la construction de la classe de base virtuellement héritée ( Top ). Sinon, dans le scénario d'héritage multiple/diamant-de-la-mort (où l'héritage virtuel est classiquement utilisé), le compilateur ne saurait pas laquelle des deux classes "intermédiaires" devrait construire la classe de base unique. Le site Middle L'appel du constructeur de l'entreprise à la Top Le constructeur de l'utilisateur est donc ignoré lorsque Middle est en cours de construction à partir de Bottom :

class Top {
    public:
        Top() {}
}

class Middle: virtual public Top {
    public:
        Middle(): Top() {} // Top() is ignored if Middle constructed through Bottom()
}

class Bottom: public Middle {
    public:
        Bottom(): Middle(), Top() {}
}

Donc, dans l'approche 2) ou 3) de votre question, Bottom() ne peut pas appeler Top() parce qu'il est hérité de manière privée (par défaut, comme dans votre code, mais cela vaut la peine de le rendre explicite) dans le fichier Middle et n'est donc pas visible dans Bottom . ( source )

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