Comment définir sealed class en C++?

Comment arrêter la classe d'hériter d'une autre classe.

51
demandé sur Nawaz 2011-01-17 15:12:00

6 réponses

C++11 solution

dans C++11, Vous pouvez sceller une classe en utilisant le mot-clé final dans la définition comme:

class A final  //note final keyword is used after the class name
{
   //...
};

class B : public A  //error - because class A is marked final (sealed).
{                   //        so A cannot be derived from.
   //...
};

pour connaître les autres utilisations de final, voir ma réponse ici:


C++03 solution 151960920"

Le code de Bjarne Stroustrup : puis-je arrêter les gens qui dérivent de ma classe?

class Usable;
class Usable_lock {
    friend class Usable;
private:
    Usable_lock() {}
    Usable_lock(const Usable_lock&) {}
};

class Usable : public virtual Usable_lock {
public:
    Usable();
    Usable(char*);
};
Usable a;

class DD : public Usable { };

DD dd;  // error: DD::DD() cannot access
        // Usable_lock::Usable_lock(): private  member

Generic_lock

donc nous pouvons utiliser le modèle pour faire le Usable_lock assez générique pour sceller n'importe quelle classe:

template<class T>
class  Generic_lock 
{
    friend T;
    Generic_lock() {}                     //private
    Generic_lock(const Generic_lock&) {}  //private
};

class Usable : public virtual Generic_lock<Usable>
{
public:
    Usable() {}
};

Usable a; //Okay
class DD : public Usable { };

DD dd; //Not okay!
80
répondu Nawaz 2017-05-23 12:09:44

il y a deux façons, la simple bon marché, et la correcte. Les deux réponses de @Naveen et @Nawaz traitent de la bonne réponse, qui nécessite la création manuelle d'une classe sealer pour chaque classe que vous voulez réellement sceller.

la méthode qui n'est pas infaillible, qui est utilisée dans les Bibliothèques adobe, utilise une classe de modèles pour cela. Le problème est que vous ne pouvez pas déclarer l'argument de modèle comme un ami, et cela signifie que vous aurez à passer de private à protected :

template <typename T>
class sealer {
protected: sealer() {}
};
class sealed : virtual sealer<sealed> {};

et vous pouvez l'automatiser avec une macro (Je ne me souviens pas de la saveur exacte de la macro dans le code D'Adobe):

#define seal( x ) virtual sealer<x>
class sealed : seal(sealed) 
{};

maintenant, cela va attraper les gens qui par erreur essayer d'hériter sans savoir qu'ils ne devraient pas:

class derived : sealed {};
int main() {
   derived d;  // sealer<T>::sealer() is protected within this context
}

mais il ne sera pas inhiber les gens que vraiment veulent dériver, car ils peuvent gagner accès au constructeur par le biais du modèle lui-même:

class derived : sealed, sealer<sealed> {};
int main() {
   derived d;
};

Je ne suis pas sûr que cela va changer dans C++0x, je pense que je me souviens de quelques discussions sur le fait de savoir si un modèle de classe serait autorisé à être ami avec l'un de ses arguments, mais dans une recherche rapide à travers le projet, je ne peux pas vraiment dire. Si cela était autorisé, ce serait une bonne solution générique:

template <typename T>
class sealer {
   sealer() {}
   friend class T; // Incorrect in C++03
};
10
répondu David Rodríguez - dribeas 2013-08-20 12:23:19

C++11 ajoute la capacité d'empêcher l'héritage des classes ou tout simplement d'empêcher les méthodes supérieures dans les classes dérivées. Ceci est fait avec l'identifiant spécial final . Par exemple:

class Base final { };

class Derived1 : Base { }; // ill-formed because the class Base has been marked final

ou

class Base {
    virtual void f() final;
};

class Derived : Base {
    void f(); // ill-formed because the virtual function Base::f has been marked final

notez que final n'est pas un mot-clé de langue. Il s'agit techniquement d'un identifiant; il n'acquiert un sens particulier que s'il est utilisé dans ces contextes spécifiques. Dans tout autre endroit, il peut être un identificateur valide.

7
répondu AzP 2018-01-24 14:16:12

D'après de Bjarne Stroustrup http://www.stroustrup.com/bs_faq2.html#no-derivation FAQ avec une petite modification sans ami utilisation de mot clé:

// SEALED CLASS DEFINITIONS
class Usable_lock {
protected:
    Usable_lock() {}
    Usable_lock(const Usable_lock&) {}
};
#define sealed_class private virtual Usable_lock

// SEALED CLASS USAGE EXMAPLES
class UsableLast : sealed_class {
public:
    UsableLast(){}
    UsableLast(char*){}
};
class DD : public UsableLast {};

// TEST CODE
template <class T> T createInstance() {
    return T();
}
int main()
{
    createInstance<UsableLast>();
//  createInstance<DD>();
    return 0;
}
0
répondu bruziuz 2014-12-29 16:43:04

le code suivant montre comment définir une classe scellée en C++/CLI.

class A sealed
{
    //here goes the class code
};

class B : public A
{
};

Maintenant B : ne peut pas hériter d'Un comme il a été déclaré que les scellés'. Aussi une explication détaillée sur sealed mot clé peut être trouvé ici http://msdn.microsoft.com/en-us/library/0w2w91tf.aspx

mise à jour: ajouté C++/CLI , d'autres réponses ont également montré la dernière façon C++11 de réaliser la même chose en utilisant le mot-clé final .

-1
répondu darth_coder 2018-05-16 09:36:52

vous ne pouvez pas. C++ n'est pas du Java ou du C#. Et ça ne sert à rien, jamais, IMHO.

-10
répondu wilx 2011-01-17 12:13:04