web-dev-qa-db-fra.com

Pourquoi n'y a-t-il pas de classe de base en C ++?

Question rapide: à partir d'un point de vue de design, pourquoi, en C++, il n'y a pas de classe de base mère, qu'est-ce qui est habituellement object dans d'autres langues?

84
slezica

La décision définitive se trouve dans FAQ de Stroustrup . En bref, cela ne transmet aucune signification sémantique. Cela aura un coût. Les modèles sont plus utiles pour les conteneurs.

Pourquoi C++ n'a-t-il pas un objet de classe universelle?

  • Nous n'avons pas besoin d'une: la programmation générique fournit des solutions de remplacement de type statique dans la plupart des cas. D'autres cas sont traités en utilisant plusieurs héritages.

  • Il n'y a pas de classe universelle utile: un véritable universel ne porte aucune sémantique à part entière.

  • Une classe "universelle" encourage la réflexion bâclée sur les types et les interfaces et conduit à une vérification excessive du temps d'exécution.

  • L'utilisation d'une classe de base universelle implique des coûts: les objets doivent être alloués à être polymorphes; Cela implique des coûts de mémoire et d'accès. Les objets de tas ne supportent pas naturellement la sémantique de la copie. Les objets de tas ne supportent pas de comportement spécifique (qui complique la gestion des ressources). Une classe de base universelle encourage l'utilisation de dynamic_cast et d'autres vérifications de temps d'exécution.

115
Captain Giraffe

Pensons d'abord pourquoi vous voudriez avoir une classe de base en premier lieu. Je peux penser à quelques raisons différentes:

  1. Soutenir les opérations génériques ou les collections qui fonctionneront sur des objets de tout type.
  2. Inclure diverses procédures communes à tous les objets (tels que la gestion de la mémoire).
  3. Tout est un objet (pas de primitives!). Certaines langues (comme l'objectif-c) n'ont pas cela, ce qui rend les choses assez désordonnées.

Ce sont les deux bonnes raisons que les langues du SmallTalk, Ruby et la marque de base-C ont des classes de base (techniquement, l'objectif-C n'a pas vraiment de classe de base, mais pour tous intention et objectifs, cela fait).

Pour # 1, la nécessité d'une classe de base qui unifie tous les objets sous une seule interface est évitée par l'inclusion de modèles en C++. Par exemple:

void somethingGeneric(Base);

Derived object;
somethingGeneric(object);

est inutile, lorsque vous pouvez maintenir l'intégrité de type tout au long du polymorphisme paramétrique!

template <class T>
void somethingGeneric(T);

Derived object;
somethingGeneric(object);

Pour # 2, alors que dans l'objectif-C, les procédures de gestion de la mémoire font partie de la mise en œuvre d'une classe et sont héritées de la classe de base, la gestion de la mémoire en C++ est effectuée à l'aide de la composition plutôt que de l'héritage. Par exemple, vous pouvez définir un emballage à pointeur intelligent qui effectuera un comptage de référence sur des objets de n'importe quel type:

template <class T>
struct refcounted
{
  refcounted(T* object) : _object(object), _count(0) {}

  T* operator->() { return _object; }
  operator T*() { return _object; }

  void retain() { ++_count; }

  void release()
  {
    if (--_count == 0) { delete _object; }
  }

  private:
    T* _object;
    int _count;
};

Ensuite, au lieu d'appeler des méthodes sur l'objet lui-même, vous appelez des méthodes dans son enveloppe. Cela permet non seulement une programmation plus générique: il vous permet également de séparer les préoccupations (car idéalement, votre objet devrait être plus préoccupé par ce qu'il devrait faire, que sa mémoire doit être gérée dans différentes situations).

Enfin, dans une langue qui a à la fois des primitives et des objets réels tels que C++, les avantages d'avoir une classe de base (une interface cohérente pour tout valeur) sont perdues, Depuis lors, vous avez certaines valeurs qui ne peuvent pas être conformes à cette interface. Afin d'utiliser des primitives dans ce type de situation, vous devez les soulever dans des objets (si votre compilateur ne le fera pas automatiquement). Cela crée beaucoup de complications.

Donc, la réponse courte à votre question: C++ n'a pas de classe de base car, ayant un polymorphisme paramétrique par des modèles, il n'a pas besoin de.

44
Jonathan Sterling

Le paradigme dominant des variables C++ est une valeur de passage, pas de réussite-réf. Forcer tout pour être dérivé d'une racine Object _ allait les transmettre par une erreur d'erreur IPSE Facto.

(Parce que l'acceptation d'un objet par valeur en tant que paramètre, seriez par définition le couper et retirer son âme).

Ceci est indésirable. C++ fait penser à ce que vous souhaitiez une sémantique de valeur ou de référence, vous donnant le choix. C'est une grande chose dans l'informatique de performance.

15
sehe

Le problème est qu'il y a là IS Un tel type en C++! C'est void. :-) Tout pointeur peut être implicitement implicitement jeté à void *, y compris les pointeurs à des types de base, classes sans table virtuelle et classes avec table virtuelle.

Comme il devrait être compatible avec toutes ces catégories d'objets, void lui-même ne peut pas contenir de méthodes virtuelles. Sans fonctions virtuelles et RTTI, aucune information utile sur le type ne peut être obtenue à partir de void (il correspond à chaque type, il ne peut donc pas indiquer que des choses qui sont vraies pour chaque type), mais les fonctions virtuelles et RTTI rendraient des types simples. Inefficace et STOP C++ d'être une langue appropriée pour une programmation de bas niveau avec un accès à la mémoire directe, etc.

Donc, il y a un tel type. Il offre simplement une interface très minimaliste (en fait, vide) en raison de la nature de faible niveau de la langue. :-)

6
Ellioh