Question

Pourquoi C ++ pas un constructeur virtuel?

Pas de solution correcte

Autres conseils

L'entendre de la bouche de :) du cheval.

De de Bjarne Stroustrup de C ++ style et FAQ Technique Pourquoi nous n'avons pas les constructeurs virtuels?

  

Un appel virtuel est un mécanisme pour faire le travail donné partiel   information. En particulier, « virtuel » nous permet d'appeler une fonction   sachant que toutes les interfaces, et non le type exact de l'objet. À   créer un objet dont vous avez besoin des informations complètes. vous en particulier,   besoin de connaître le type exact de ce que vous voulez créer. Par conséquent,   un « appel à un constructeur » ne peut pas être virtuel.

L'entrée de FAQ continue de donner le code pour un moyen d'atteindre cette fin sans un constructeur virtuel.

Les fonctions virtuelles fournissent essentiellement le comportement polymorphique. Autrement dit, lorsque vous travaillez avec un objet dont le type dynamique est différente de la statique (temps de compilation) de type avec lequel il est appelé, il fournit un comportement qui est approprié pour réelle type d'objet au lieu de le type statique de l'objet.

Maintenant, essayez d'appliquer ce genre de comportement à un constructeur. Lorsque vous construisez un objet type statique est toujours le même que le type d'objet réel depuis:

  

Pour construire un objet, un constructeur doit le type exact de l'objet est de créer [...] De plus [...] vous ne pouvez pas avoir un pointeur vers un constructeur

(Bjarne Stroustup (P424 C ++ langage de programmation SE))

Nous, il est tout simplement pas un constructeur: -)

struct A {
  virtual ~A() {}
  virtual A * Clone() { return new A; }
};

struct B : public A {
  virtual A * Clone() { return new B; }
};

int main() {

   A * a1 = new B;
   A * a2 = a1->Clone();    // virtual construction
   delete a2;
   delete a1;
}

raisons sémantiques mises à part, il n'y a pas vtable jusqu'à ce que l'objet est construit, permettant ainsi une désignation virtuelle inutile.

Résumé : le C ++ standard peut spécifier une notation et de comportement pour s "constructeur virtuel" qui est assez intuitive et pas trop difficile pour les compilateurs à l'appui, mais pourquoi faire un changement de base pour ce en particulier lorsque le fonctionnalité peut déjà être proprement mis en œuvre à l'aide create() / clone() (voir ci-dessous)? Il est loin d'être aussi utile que de nombreuses autres propositions de la langue dans le pipeline.

Discussion

Soit postulons un mécanisme "constructeur virtuel":

Base* p = new Derived(...);
Base* p2 = new p->Base();  // possible syntax???

Dans ce qui précède, la première ligne construit un objet Derived, donc la table d'expédition virtuelle *p peut raisonnablement fournir un « constructeur virtuel » pour une utilisation dans la deuxième ligne. (Des dizaines de réponses sur cette page en indiquant « l'objet n'existe pas encore si la construction virtuelle est impossible » sont inutilement myopes axés sur l'objet à être construit.)

La deuxième ligne postule la notation new p->Base() pour demander l'allocation dynamique et la construction par défaut d'un autre objet de Derived.

Notes:

Le compilateur devrait:

  • savoir la quantité de mémoire nécessaire Derived, soit en appelant une fonction implicite de virtual sizeof ou ayant de telles informations via RTTI
  • operator new(size_t) d'appel à allouer de la mémoire
  • invoquer Derived() avec le placement new.

ou

  • créer une entrée vtable supplémentaire pour une fonction qui combine l'allocation et la construction dynamique

- il ne semble pas insurmontable pour préciser et mettre en œuvre les constructeurs virtuels, mais la question à un million de dollars est: comment serait-il mieux que ce qui est possible à l'aide existants C ++ fonctionnalités du langage ...? Personnellement, Je ne vois aucun avantage sur la solution ci-dessous.


clone

`()` et `create ()`

Le C ++ FAQ documente un idiome "constructeur virtuel" , contenant virtual create() et méthodes clone() à défaut du produit d'assemblage ou de copie construire un nouvel objet allouée dynamiquement:

class Shape {
  public:
    virtual ~Shape() { } // A virtual destructor
    virtual void draw() = 0; // A pure virtual function
    virtual void move() = 0;
    // ...
    virtual Shape* clone() const = 0; // Uses the copy constructor
    virtual Shape* create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
  public:
    Circle* clone() const; // Covariant Return Types; see below
    Circle* create() const; // Covariant Return Types; see below
    // ...
};
Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }

Il est également possible de modifier ou de surcharge create() d'accepter des arguments, bien que pour correspondre à la signature de la fonction de virtual de la classe de base / interface, les arguments sur Remplacements doivent correspondre exactement à l'une des surcharges de classe de base. Wie ces installations explicites fournies par l'utilisateur, il est facile d'ajouter l'enregistrement, l'instrumentation, modifier l'allocation de mémoire etc ..

Vous pouvez trouver un exemple et la raison technique pour laquelle il n'a pas le droit de réponse de l » @stefan de. Maintenant, une réponse logique à cette question, selon moi, est:

La principale utilisation du mot-clé virtuelle est de permettre le comportement polymorphique quand nous ne savons pas quel type de l'objet le pointeur de la classe de base pointera.

Mais pensez à cela est de façon plus primitive, pour l'utilisation de la fonctionnalité virtuelle que vous aurez besoin d'un pointeur. Et qu'est-ce qu'un pointeur besoin? Un objet pour pointer vers! (Compte tenu de cas pour une exécution correcte du programme)

Donc, nous avons besoin fondamentalement un objet qui existe déjà quelque part dans la mémoire (nous ne sommes pas préoccupés par la façon dont la mémoire a été allouée, il peut être au moment de la compilation ou soit l'exécution) afin que notre pointeur peut pointer correctement à cet objet.

Maintenant, pensez à la situation sur le moment où l'objet de la classe à signaler est assignée une mémoire -> Son constructeur sera appelé automatiquement à cette instance elle-même

On peut donc voir que nous ne devons pas vraiment à se soucier du constructeur étant virtuel, parce que dans tous les cas que vous souhaitez utiliser un comportement polymorphique notre constructeur aurait déjà été exécuté faisant l'objet de notre prêt à être utilisé!

Bien que le concept des constructeurs virtuels ne correspond pas bien puisque le type d'objet est pré-requis pour la création d'objets, son. Pas renversées completly

Le modèle de conception « méthode usine » de GOF utilise le « concept » du constructeur virtuel, qui est handly dans certaines situations de conception.

Les fonctions virtuelles en C ++ sont une implémentation de polymorphisme d'exécution, et ils le feront primordial de la fonction. En général, le mot-clé virtual est utilisé en C ++ lorsque vous avez besoin comportement dynamique. Il ne fonctionnera que si l'objet existe. Alors que les constructeurs sont utilisés pour créer les objets. Constructors seront appelés au moment de la création d'objets.

Donc, si vous créez le constructeur comme virtual, selon la définition du mot-clé virtuel, il devrait avoir l'objet existant à utiliser, mais le constructeur est utilisé pour créer l'objet, de sorte que ce cas n'existera jamais. Donc, vous ne devriez pas utiliser le constructeur comme virtuel.

Alors, si nous essayons de déclarer compilateur constructeur virtuel lancer une erreur:

  

Constructors ne peuvent pas être déclarés virtuels

Quand les gens posent une question comme ça, je me plais à penser à moi-même « ce qui se passerait si cela était effectivement possible? » Je ne sais pas vraiment ce que cela signifie, mais je suppose que cela aurait quelque chose à voir avec être en mesure de passer outre la mise en œuvre du constructeur en fonction du type dynamique de l'objet créé.

Je vois un certain nombre de problèmes potentiels avec cela. D'une part, la classe dérivée ne sera pas complètement construit au moment où le constructeur virtuel est appelé, donc il y a des problèmes potentiels avec la mise en œuvre.

En second lieu, ce qui se passerait dans le cas de l'héritage multiple? Votre constructeur virtuel serait appelé plusieurs fois sans doute, vous aurez alors besoin d'avoir un moyen de savoir que l'on a appelé.

En troisième lieu, en général au moment de la construction, l'objet n'a pas la table virtuelle entièrement construit, cela signifie qu'il faudrait un changement important à la spécification du langage pour permettre le fait que le type dynamique de l'objet serait connu au moment de la construction. Cela permettrait alors le constructeur de la classe de base pour appeler peut-être d'autres fonctions virtuelles au moment de la construction, avec un type de classe dynamique construit pas complètement.

Enfin, comme quelqu'un d'autre a signalé que vous pouvez mettre en œuvre une sorte de constructeur virtuel utilisant statiques « créer » ou des fonctions de type « init » qui font essentiellement la même chose en tant que constructeur virtuel ferait.

Les fonctions virtuelles sont utilisées pour appeler des fonctions en fonction du type d'objet pointé par le pointeur, et non le type de pointeur lui-même. Mais un constructeur n'est pas « opposabilité ». Il est appelé une seule fois lorsqu'un objet est déclaré. Ainsi, un constructeur ne peut pas être virtuel en C ++.

Vous ne devriez pas appeler la fonction virtuelle au sein de votre constructeur soit. Voir: http://www.artima.com/cppsource/nevercall.html

En outre, je ne suis pas sûr que vous avez vraiment besoin d'un constructeur virtuel. Vous pouvez réaliser la construction polymorphes sans elle. Vous pouvez écrire une fonction qui construira votre objet en fonction des paramètres nécessaires

Une table virtuelle (vtable) est effectué pour chaque classe comportant un ou plusieurs « virtuelles »-fonctions. Chaque fois qu'un objet est créé de cette classe, il contient un « pointeur virtuel » qui pointe vers la base correspondante vtable. Chaque fois qu'il ya un appel de fonction virtuelle, le vtable est utilisé pour résoudre à l'adresse de fonction.     Constructor ne peut pas être virtuel, parce que quand le constructeur d'une classe est exécutée il n'y a pas vtable dans la mémoire, signifie pas pointeur virtuel défini. D'où le constructeur doit toujours être non-virtuelle.

Cant nous disons simplement comme .. Nous ne pouvons pas hériter constructeurs. Donc, il n'y a pas de point de les déclarer virtuel parce que le virtuel fournit polymorphisme.

Le mécanisme virtuel ne fonctionne que lorsque vous avez un pointeur de classe basée sur un objet de classe dérivée. La construction a ses propres règles pour l'appel des constructeurs de classe de base, essentiellement classe base dérivée. Comment un constructeur virtuel pourrait être utile ou appelé? Je ne sais pas ce que d'autres langages, mais je ne vois pas comment un constructeur virtuel pourrait être utile ou même mis en œuvre. La construction doit avoir eu lieu pour le mécanisme virtuel de sens et la construction doit également avoir eu lieu pour les structures vtable avoir été créé qui fournit les mécanismes du comportement polymorphique.

Il y a une raison très simple:. Constructors sont des fonctions efficacement statiques et en C ++ aucune fonction statique peut être virtuel

Si vous avez beaucoup d'expérience avec C ++, vous savez tout sur la différence entre les fonctions statiques et membres. Les fonctions statiques sont associées à la classe, et non pas les objets (instances), de sorte qu'ils ne voient pas « ce » pointeur. Seules les fonctions membres peuvent être virtuelles, car le vtable- la table cachée des pointeurs de fonction qui rend « virtuelle » est vraiment un MAIN-membre de données de chaque objet.

Maintenant, quel est le travail du constructeur? Il est dans le constructeur Name- « T » T initialise objets comme ils sont attribués. Cela empêche automatiquement d'être une fonction membre! Un objet a Exister avant qu'il ait un pointeur « ceci » et donc un vtable. Cela signifie que même si le langage des constructeurs traités comme des fonctions (il n'a pas, pour des raisons connexes je ne vais pas entrer dans), ils auraient à être des fonctions membres statiques.

Une excellente façon de voir est de regarder le modèle « Factory », en particulier les fonctions d'usine. Ils font ce que vous êtes après, et vous remarquerez que si la classe T a une méthode de fabrication, il est toujours STATIC. Il doit être.

constructeur virtuel C est de ne pas exemple possible.For vous ne pouvez pas marquer un constructeur comme virtual.Try ce code

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        virtual aClass()
        {   
        }  
};
int main()
{
    aClass a; 
}

Il provoque un code error.This tente de déclarer un constructeur comme virtuel. Maintenant, nous allons essayer de comprendre pourquoi nous utilisons mot-clé virtuel. mot-clé virtuel est utilisé pour fournir polymorphisme moment de l'exécution. Par exemple, essayez ce code.

#include<iostream.h>
using namespace std;
class aClass
{
    public:
        aClass()
        {
            cout<<"aClass contructor\n";
        }
        ~aClass()
        {
            cout<<"aClass destructor\n";
        }

};
class anotherClass:public aClass
{

    public:
        anotherClass()
        {
            cout<<"anotherClass Constructor\n";
        }
        ~anotherClass()
        {
            cout<<"anotherClass destructor\n";
        }

};
int main()
{
    aClass* a;
    a=new anotherClass;
    delete a;   
    getchar(); 
}

Dans principale a=new anotherClass; alloue une mémoire pour anotherClass dans un a pointeur déclaré que le type de aClass.This provoque à la fois le constructeur (en aClass et anotherClass) pour appeler automatically.So nous ne devons marquer constructeur comme virtual.Because lorsqu'un objet est créé, il doit suivre la chaîne de création (c.-à d'abord la base, puis les classes dérivées). Mais quand nous essayons de supprimer un delete a; il provoque appeler seulement la base destructor.So nous devons gérer le destructor en utilisant le mot virtuel. Donc, constructeur virtuel n'est pas possible, mais destructor virtuelle est .REMERCIE

Si vous pensez logiquement sur la façon dont les constructeurs travail et quel est le sens / utilisation d'une fonction virtuelle est en C ++, vous vous rendrez compte qu'un constructeur virtuel serait dénué de sens en C ++. Déclarant quelque chose de virtuel en C ++ signifie qu'il peut être remplacé par une sous-classe de la classe actuelle, mais le constructeur est appelé lorsque l'objection est créé, à ce moment-là, vous ne pouvez pas être en train de créer une sous-classe de la classe, vous devez être la création de la classe donc il n'y aurait jamais besoin de déclarer un constructeur virtuel.

Et une autre raison est, les constructeurs ont le même nom que son nom de classe et si nous déclarons constructeur comme virtuel, alors il devrait être redéfini dans sa classe dérivée avec le même nom, mais vous ne pouvez pas avoir le même nom de deux Des classes. Il est donc impossible d'avoir un constructeur virtuel.

  1. Quand un constructeur est invoqué, bien qu'il n'y ait pas d'objet créé jusqu'à ce moment-là, nous savons encore le genre d'objet qui sera créé va parce que le constructeur spécifique de la classe à laquelle l'objet appartient à a déjà été appelé.

    mot-clé Virtual associé à un moyen de fonction fonction d'un type d'objet particulier est va être appelé.

    Alors, ma pensée dit qu'il n'y a pas besoin de faire le constructeur virtuel, car déjà le constructeur désiré dont l'objet est va être créé a été invoqué et faire constructeur virtuel est juste une chose redondante à faire parce que le object- constructeur spécifique a déjà été invoqué et c'est identique à l'appel fonction spécifique à la classe qui est réalisé par le mot-clé virtuel.

    Bien que la mise en œuvre intérieure ne permettra pas constructeur virtuel pour des raisons liées VPTR et vtable.

  1. Une autre raison est que C ++ est un langage statiquement typé et nous avons besoin de connaître le type d'une variable à la compilation.

    Le compilateur doit être au courant du type de classe pour créer l'objet. Le type d'objet à créer est une décision de compilation.

    Si nous faisons le constructeur virtuel, cela signifie que nous ne avons pas besoin de connaître le type de l'objet à la compilation (c'est ce que la fonction virtuelle fournir. On n'a pas besoin de connaître l'objet réel et juste besoin de la pointeur de base pour pointer un objet réel appeler des fonctions virtuelles de l'objet pointu sans connaître le type de l'objet) et si nous ne connaissons pas le type de l'objet au moment de la compilation alors il est contre les langues statiquement typés. Et par conséquent, le polymorphisme d'exécution ne peut être atteint.

    Par conséquent, Constructor ne sera pas appelé sans connaître le type de l'objet à la compilation. Et si l'idée de faire un constructeur virtuel échoue.

Le Vpointer est créé au moment de la création d'objets. vpointer existe l'habitude avant la création d'objets. donc il n'y a pas de point de rendre le constructeur comme virtuel.

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