Question

Dire que j'ai une classe appelée « base », et une classe appelée « dérivée » qui est une sous-classe de base et accès des méthodes et des membres protégés de la base.

Ce que je veux faire est maintenant faire en sorte que pas d'autres classes peuvent sous-classe dérivée. En Java je peux accomplir cela en déclarant la classe dérivée « finale ». Est-il un truc C ++ qui peut me donner le même effet?

(Idéalement je voudrais faire en sorte qu'aucune autre classe que dérivée peut sous-classe de base aussi bien. Je ne peux pas mettre juste tout le code dans la même classe ou d'utiliser le mot-clé ami, depuis la base et sont tous deux Derived basé sur un modèle, avec la base ayant moins d'arguments de modèle que Derived ne ....)

Était-ce utile?

La solution

Au 11 C ++, vous pouvez ajouter le mot-clé final (techniquement un identifiant spécial car il est pas vraiment un mot-clé) à votre classe, par exemple

class Derived final
{
...

Vous pouvez en savoir plus sur le mot-clé final à http: //en.wikipedia. org / wiki / C ++ 11 # Explicit_overrides_and_final

Autres conseils

Vous pouvez avoir un constructeur privé pour « Derived » et un public static Créer fonction pour instanciation

La meilleure façon d'interdire subclassing est en rendant le constructeur privé:

class Foo
{
private:
    Foo() {}

public:
    static Foo* CreateFoo() { return new Foo; }
};

Edit: Merci à Indeera de remarquer que ce besoin d'une méthode d'usine statique

Il n'y a pas de façon simple et propre pour le faire.

Qu'est-ce que la bibliothèque standard n'est tout simplement faire la nonvirtual destructor. Cela ne l'empêche pas subclassing, mais il est un signal fort aux utilisateurs qui ne sont pas conçus pour l'héritage, et cela signifie que vous devez être très prudent lorsque vous utilisez la classe dérivée.

En fin de compte, vous besoin pour faire absolument subclassing impossible ? Est-il pas assez bon pour indiquer que « provenant de cette classe est une mauvaise idée »?

Les gens peuvent toujours casser votre code s'ils veulent vraiment. Le mieux que vous pouvez faire est de les sensibiliser à ce qu'ils devraient et ne devraient pas faire, et nous espérons qu'ils ne seront pas activement essayer de casser votre code.

Protégez votre code contre Murphy, pas Machiavel. ;)

Puisque vous utilisez des modèles que je pensais que la dernière partie de votre question sur la prévention de toute catégorie autre que dérivé sous-classe de base pourrait être effectuée en utilisant des spécialisations partielles appropriées.

Le code suivant est ce que je suis venu avec, mais la complexité requise ne fait que renforcer la réponse par jalf. Est-ce que ça vaut le coup? Si tout cela a m'a permis de comprendre la spécialisation partielle plus de travail une technique que je pourrais jamais utiliser dans la pratique.

J'utilise COMMON pour indiquer un paramètre de modèle partagé entre la base et dérivés et EXTRA pour indiquer les paramètres supplémentaires que vous dites dérivés a. Les chiffres réels de ceux-ci pourraient être tout ce que je vient de se passer d'avoir choisi un et deux pour ceux-ci, respectivement.

// Forward declaration of class Derived
template< class COMMON
        , class EXTRA1
        , class EXTRA2 >
class Derived;


// Definition of general class template Base
template< class SUBCLASS
        , class COMMON >
class Base
{
private:
    Base() {}
};


// Definition of partial specialisation of template class Base to open up
// access to the constructor through friend declaration.
template< class COMMON
        , class EXTRA1
        , class EXTRA2 >
class Base< Derived< COMMON, EXTRA1, EXTRA2 >
          , COMMON >
{
private:
    Base() {}

    friend class Derived< COMMON, EXTRA1, EXTRA2 >;
};


// Definition of class Derived
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class Derived
    : public Base< Derived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    static Derived* create() { return new Derived; }

private:
    Derived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
                    , COMMON >()
    {
    }
};


// Definition of class HonestDerived.
// It supplies itself as the SUBCLASS parameter to Base.
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class HonestDerived
    : public Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    HonestDerived() : Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
                          , COMMON >()
    {
    }
};


// Definition of class DishonestDerived
// It supplies Derived rather than itself as the SUBCLASS parameter to Base.
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class DishonestDerived
    : public Base< Derived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    DishonestDerived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
                             , COMMON >()
    {
    }
};


template< class COMMON, class EXTRA1, class EXTRA2 >
class DerivedFromDerived
    : public Derived< COMMON, EXTRA1, EXTRA2 >
{
public:
    DerivedFromDerived() : Derived< COMMON, EXTRA1, EXTRA2 >()
    {
    }
};

// Test partial specialisation gives Derived access to the Base constructor
Derived< int, float, double >* derived
    = Derived< int, float, double >::create();

// Test that there is no access to the Base constructor for an honest subclass
// i.e. this gives a compiler error
HonestDerived< int, float, double > honestDerived;

// Test that there is no access to the Base constructor for a dishonest subclass
// i.e. this gives a compiler error
DishonestDerived< int, float, double > dishonestDerived;

// Test that there is no access to the Derived constructor
// i.e. this gives a compiler error
DerivedFromDerived< int, float, double > derivedFromDerived;

Ce code a été testé avec gcc 4.3.2.

Notez qu'une alternative à la déclaration d'ami serait de rendre le constructeur protégé dans la spécialisation partielle de la base mais qui permettrait à des classes comme DishonestDerived de travailler.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top