Effective C ++ clause 39: (a utilisation rationnelle et judicieuse de l'héritage privé) de l'héritage orienté objet

Tout d'abord, parlez-nous de la syntaxe de l'héritage privé

  • Une classe dérivée privée d'hériter après la classe de base:
    • ① Tout le contenu (publique, protégée, privée) classe de base dans une classe dérivée n'est pas accessible
    • ② objets de classe dérivée ne peuvent plus être convertis en un objet de classe de base
    • ③ peut encore remplacer la méthode de l'élément de la classe de base / masquer la classe de base

Deux, des moyens d'héritage privé quoi que ce soit?

  • des moyens d'héritage privés mis en oeuvre par des termes de (selon réaliser sur quelque chose):
    • Supposons que vous laissez le privé héritées de la classe D à la classe B, destinée à l' utilisation de certaines caractéristiques de la classe B pour atteindre la classe D , pas d' autre sens
    • Avec 34 termes appartiennent: des moyens d'héritage privés qui mettent en œuvre qu'une partie (qui est déjà mis en œuvre dans la fonction de la classe de base) est héritée, la partie d'interface (la classe de base n'est définie encore atteint) doit être omis
  • Relation avec le modèle complexe de classe:
    • La classe de mode composite (composition) à l' article 38, dans lequel la classe composite a aussi un sentiment de « est mis en oeuvre en termes -de » la
    • Les deux ont le même sens, mais il est recommandé: l' utilisation du composite possible, si nécessaire en utilisant l' héritage privé
    • Quand il est nécessaire d'utiliser privé?
      • Principalement lorsque les membres protégés et / ou des fonctions virtuelles impliquées sont entrés. Lorsque la classe de base de classe dérivée veulent accéder composant de neutralisation protégé ou un groupe d'une ou plusieurs fonctions virtuelles de classe souhaitée
      • Un autre cas est que lorsque suffisamment d'espace stakes pilier lancé héritage privé (décrit ci-dessous)

En troisième lieu, le cas de démonstration

  • Supposons que nous ayons une telle demande:
    • Nous avons une classe Widget, veut maintenant connaître le nombre de fonction membre est appelé Widget
    • Maintenant, nous modifions absolument classe Widget, il enregistre le nombre de fois que chaque fonction membre est appelée
    • Pour ce faire, nous définissons la minuterie suivante qui périodiquement des données statistiques (nombre de statistiques pour chaque fonction de membre est appelé)
class Timer {
public:
    explicit Timer(int tickFrequency);
    virtual void onTick()const; //定时器每滴答一次,此函数就被自动调用一次
};
  • Maintenant, nous devons:
    • classe Timer sera réglée en fonction de la fréquence des tiques en avant, chaque tick est appelée fonction virtuelle
    • Maintenant, nous avons besoin de la classe Widget hérite de la minuterie, puis redéfinir la fonction virtuelle, puis utiliser cette fonction pour des données statistiques Widget (nombre de statistiques pour chaque fonction de membre est appelé)

① mauvaise approche: l'héritage public d'une manière

  • La mauvaise façon est de laisser Widget dans une voie publique à Hériter Timer, puis réécrire sa fonction virtuelle
class Timer {
public:
    explicit Timer(int tickFrequency);
    virtual void onTick()const; //定时器每滴答一次,此函数就被自动调用一次
};

class Widget :public Timer {
public:
    virtual void onTick()const;
};
  • Pourquoi erreur:
    • Est-une relation est similaire: nous savons que c'est un Widget Timer, il ne faut pas toujours faire appel à une fonction Widget onTick (), non? Cette affiche très étrange
    • De plus, le conseil serait contraire aux termes de 18: Rendre les interfaces faciles à utiliser correctement, ne peut pas facilement être mal utilisés

② hériter chemin privé

  • Afin de compléter les exigences ci-dessus, nous pouvons laisser le widget d'une manière privée héritée minuterie
  • Code est la suivante:
class Timer {
public:
    explicit Timer(int tickFrequency);
    virtual void onTick()const; //定时器每滴答一次,此函数就被自动调用一次
};

class Widget :private Timer {
private:
    virtual void onTick()const; //查看Widget的数据..等等
};
  • Nous réécrivons en Wiget dans la fonction onTick (), mais déclarerons comme privé, il ne peut pas être déclarée comme interfaces publiques, parce que si elle est déclarée comme public, encore une fois avec l'héritage du public est similaire à ce qui précède

③ mis en œuvre sous la forme d'un composite

  • En termes de 38, nous avons introduit des formes complexes de classe a également un sens de « est mis en œuvre en termes -Des » , afin que nous puissions également utiliser le modèle composite pour réaliser cette fonction
  • Code est la suivante:
class Timer {
public:
    explicit Timer(int tickFrequency);
    virtual void onTick()const; //定时器每滴答一次,此函数就被自动调用一次
};

class Widget{
public:
private:
    class WidgetTimer :public Timer {
    public:
        virtual void onTick()const;
    };
    WidgetTimer timer;
};

  • Nous dégageons une classe dérivée WidgetTimer une minuterie et fonction Rewrite onTick (), puis définir un objet de classe WidgetTimer définie dans la classe Widget dans
  • Le même problème, nous recommandons l'utilisation du mode composite sans l'utilisation de l'héritage privé est recommandé pour deux raisons:
    • la classe dérivée de ① prevent Widget pour remplacer la fonction onTick ():
      • En héritage: Si Wiget a défini une classe dérivée, vous ne voulez pas classes dérivées de passer outre la fonction onTick (), mais cela ne pouvait pas arrêter
      • En mode composite: Widget classe dérivée ne peut pas avoir une chance de réécrire onTick (fonction), et parce que la classe WidgetTimer est un membre privé interne Widget, la classe dérivée peut jamais accès
    • ② dépendance de compilation Widget peut être réduite au minimum:
      • Dans l' héritage: Si l' héritage et la minuterie Widget, puis lorsque le widget est compilé les définitions du minuteur doivent savoir ( et pas seulement la déclaration), de sorte que vous pouvez contenir #include « timer.h » une telle chose dans le fichier d' en- tête dans le widget
      • Dans le mode composé: Supposons que nous modifions le composé du modèle ci - dessus, défini en dehors du widget WidgetTimer, puis un pointeur vers la définition dans le widget WidgetTimer, mais cette fois avec le widget peut WidgetTimer déclarative, aucune compilation lorsque Widget quoi que ce soit tout besoin et la minuterie. Pour les grands systèmes, ceci est une mesure très importante

Quatre, l'héritage privé Un autre scénario d'utilisation

  • : L' héritage privé est utilisé lorsque la classe de base sans aucune classe de données
  • La classe de base est généralement: pasvariables membres non statiques, aucune fonction virutal (raison de l'existence d'une telle fonctionun VPTR pour chaque objet, voir point 7), il n'y a pasclasses de base virtuelles (telles queclasses de base seronttypetraduit par une augmentation du volume, voir point 40)

présentation de cas

  • Lorsqu'une classe n'a pas de variables membres, le compilateur définira automatiquement sa taille (différents compilateurs), il est généralement 1 octet (le placement par défaut de C dans char classe vide). Par exemple:
class Empty {}; //空类

sizeof(Empty);  //1字节
  • Les règles ci-dessus sont applicables aux catégories distinctes, si elle a dérivé des classes, et les membres de la classe dérivée, cette règle disparaîtra. Par exemple:
class Empty {};

class HoldsAnint :private Empty {
private:
    int x;
};

sizeof(HoldsAnint); //4
  • Cette règle est appelée EBO: optimisation vide accumulée (optimisation de base vide). Si vous êtes très préoccupé par le programme spatial, il convient de noter que EBO
  • A noter également: EBO généralement que l'héritage unique (plutôt que l'héritage multiple) soit viable
  • Par exemple, il existe de nombreuses implémentations STL utiliseront les classes vides. Unary_func binary_function et par exemple similaire. EBO augmente rarement la taille de l'héritage d'une classe dérivée

V. Résumé

  • des moyens d'héritage privé « est mis en œuvre en termes de-(selon obtenir quelque chose). » Il est généralement plus faible que le composite de niveau (composition). Mais quand la classe dérivée a besoin d'accéder aux membres de la classe de base ou protégées doit redéfinir la fonction virtuelle héritée, donc la conception raisonnable
  • Et composite (composition) différente, l'héritage privé peut entraîner une optimisation de base vide. Ce programme est engagé aux développeurs bibliothèque « minimiser la taille de l'objet » est concerné, il peut être important
Publié 1525 articles originaux · louange won 1085 · Vues 450000 +

Je suppose que tu aimes

Origine blog.csdn.net/qq_41453285/article/details/104835285
conseillé
Classement