105 votes

Au niveau le plus profond possible, comment les fonctions virtuelles sont-elles mises en œuvre?

Nous savons tous que les fonctions virtuelles en C++, mais comment sont-ils mis en œuvre à un niveau profond?

Peut la vtable être modifié ou même directement accessibles au moment de l'exécution?

La vtable existent pour toutes les classes, ou seulement ceux qui ont au moins une fonction virtuelle?

Ne les classes abstraites ont simplement une valeur NULL le pointeur de fonction d'au moins une entrée?

Le fait d'avoir une seule fonction virtuelle ralentir l'ensemble de la classe? Ou seulement l'appel à la fonction qui est virtuel? Et la vitesse affectée si la fonction virtuelle est en fait remplacé ou pas, ou n'ont aucun effet tant que c'est virtuel.

120voto

Zach Burlingame Points 7232

Comment sont des fonctions virtuelles mises en œuvre à un niveau profond?

De "Fonctions Virtuelles en C++"

Chaque fois qu'un programme a une fonction virtuelle déclaré, en v, un tableau est construit pour la classe. La v-table se compose d'adresses pour les fonctions virtuelles pour les classes qui contiennent un ou plusieurs des fonctions virtuelles. L'objet de la classe contenant la fonction virtuelle contient un pointeur virtuel qui pointe vers l'adresse de base de la table virtuelle en mémoire. Chaque fois qu'il y a un appel de fonction virtuelle, la v-table est utilisée pour résoudre l'adresse de fonction. Un objet de la classe qui contient un ou plusieurs des fonctions virtuelles contient un pointeur virtuel appelé le vptr au tout début de l'objet dans la mémoire. Donc la taille de l'objet dans ce cas augmente en fonction de la taille du pointeur. Cette vptr contient l'adresse de base de la table virtuelle en mémoire. Notez que les tables virtuelles sont de classe spécifique, c'est à dire, il y a une seule table virtuelle pour une classe quel que soit le nombre de fonctions virtuelles qu'il contient. Cette table virtuelle contient les adresses de base d'une ou de plusieurs fonctions virtuelles de la classe. Au moment où une fonction virtuelle est appelée sur un objet, le vptr de cet objet fournit l'adresse de base de la table virtuelle de cette catégorie dans la mémoire. Cette table est utilisée pour résoudre l'appel de la fonction, car il contient les adresses de toutes les fonctions virtuelles de la classe. C'est de cette façon de liaison dynamique est résolu lors d'un appel de fonction virtuelle.

Peut la vtable être modifié ou même directement accessibles au moment de l'exécution?

Universellement, je crois que la réponse est "non". Vous pourriez faire un peu de mémoire d'amputation pour trouver la vtable, mais vous ne savez pas ce que la signature de la fonction ressemble à l'appeler. Tout ce que vous voulez atteindre avec cette possibilité (que la langue prend en charge) doit être possible sans l'accès à la vtable directement ou de le modifier lors de l'exécution. A noter aussi, le langage C++ spec ne pas spécifier que les vtables sont nécessaires - mais qui est la façon dont la plupart des compilateurs de mettre en œuvre des fonctions virtuelles.

La vtable existent pour tous les objets, ou de ceux qui ont au moins une fonction virtuelle?

Je crois que la réponse est "ça dépend de la mise en œuvre" depuis que la norme n'exige pas vtables en premier lieu. Cependant, dans la pratique, je crois que tous les compilateurs modernes seulement de créer une vtable si une classe possède au moins 1 fonction virtuelle. Il y a un espace frais généraux associés à la vtable et un temps frais généraux associés à l'appel d'une fonction virtuelle vs une fonction non virtuelle.

Ne les classes abstraites ont simplement une valeur NULL le pointeur de fonction d'au moins une entrée?

La réponse est qu'il n'est pas spécifié par la langue spec donc, cela dépend de la mise en œuvre. L'appel de la fonction virtuelle pure résultats dans un comportement indéfini si elle n'est pas définie (ce qui n'est généralement pas) (ISO/IEC 14882:2003 10.4-2). Dans la pratique, il n'allouer une fente dans la vtable pour la fonction, mais n'a pas d'attribuer une adresse à elle. Cela laisse de la vtable incomplète qui exige que les classes dérivées pour mettre en œuvre la fonction et de compléter la vtable. Certaines implémentations de faire il suffit de placer un pointeur NULL dans la vtable entrée; d'autres implémentations de placer un pointeur à un mannequin de la méthode qui fait quelque chose de semblable à une affirmation.

Notez qu'une classe abstraite peut définir une mise en œuvre d'une fonction virtuelle pure, mais cette fonction ne peut être appelée avec un personnel qualifié-id syntaxe (ie., entièrement spécifiant la classe dans le nom de la méthode, similaire à l'appel d'une méthode de classe de base d'une classe dérivée). Ceci est fait afin de fournir un outil facile à utiliser par défaut de mise en œuvre, tout en exigeant qu'une classe dérivée de fournir un remplacement.

Le fait d'avoir une seule fonction virtuelle ralentir l'ensemble de la classe ou seulement l'appel à la fonction qui est virtuel?

C'est arriver à la limite de ma connaissance, de sorte s'il vous plaît aidez-moi ici si je me trompe!

Je crois que les seules fonctions qui sont virtuels dans la catégorie de l'expérience à la fois de performances liées à l'appel d'une fonction virtuelle par rapport à un non-fonction virtuelle. L'espace supplémentaire pour la classe en est-il de toute façon. Notez que si il y a une vtable, il est à seulement 1 par classe, pas un par objet.

La vitesse affectée si la fonction virtuelle est en fait remplacée ou pas, ou n'ont aucun effet tant que c'est virtuel?

Je ne crois pas que le temps d'exécution d'une fonction virtuelle qui est remplacé diminue par rapport à l'appel de la base de la fonction virtuelle. Cependant, il y a un espace supplémentaire de surcharge pour la classe associée à la définition d'un autre vtable pour la classe dérivée par rapport à la classe de base.

Ressources Supplémentaires:

http://www.codersource.net/published/view/325/virtual_functions_in.aspx

http://en.wikipedia.org/wiki/Virtual_table

http://www.codesourcery.com/public/cxx-abi/abi.html#vtable

31voto

puetzk Points 5099
  • Peut la vtable être modifié ou même directement accessibles au moment de l'exécution?

Pas de façon portable, mais si vous n'avez pas l'esprit de sales tours, bien sûr!

Dans la plupart des compilateurs j'ai vu, la vtbl * les 4 premiers octets de l'objet, et la vtbl contenu est tout simplement un tableau de membre des pointeurs (généralement dans l'ordre où ils ont été déclarés, à la base de la classe de première). Il y a bien sûr d'autres schémas possibles, mais c'est ce que j'ai constaté, de manière générale.

class A {
  public:
  virtual int f1() = 0;
};
class B : public A {
  public:
  virtual int f1() { return 1; }
  virtual int f2() { return 2; }
};
class C : public A {
  public:
  virtual int f1() { return -1; }
  virtual int f2() { return -2; }
};

A *x = new B;
A *y = new C;
A *z = new C;

Maintenant, pour tirer des manigances...

Changer de classe au moment de l'exécution:

std::swap(*(void **)x, *(void **)y);
// Now x is a C, and y is a B! Hope they used the same layout of members!

Remplacement d'une méthode pour toutes les instances (monkeypatching une classe)

Celui-ci est un peu plus délicat, car la vtbl lui-même est sans doute dans la mémoire en lecture seule.

int f3(A*) { return 0; }

mprotect(*(void **)x,8,PROT_READ|PROT_WRITE|PROT_EXEC);
// Or VirtualProtect on win32; this part's very OS-specific
(*(int (***)(A *)x)[0] = f3;
// Now C::f1() returns 0 (remember we made x into a C above)
// so x->f1() and z->f1() both return 0

Ce dernier est plutôt enclins à faire des virus pions et le lien de la réveiller et de prendre avis, en raison de la mprotect manipulations. Dans un processus en utilisant le bit NX, il peut très bien échouer.

2voto

Michael Burr Points 181287

Cette réponse a été incorporé dans le Wiki de la Communauté réponse

  • Ne les classes abstraites ont simplement une valeur NULL le pointeur de fonction d'au moins une entrée?

La réponse c'est qu'il n'est pas précisé - l'appel de la fonction virtuelle pure résultats dans un comportement indéfini si elle n'est pas définie (ce qui n'est généralement pas) (ISO/IEC 14882:2003 10.4-2). Certaines implémentations de faire il suffit de placer un pointeur NULL dans la vtable entrée; d'autres implémentations de placer un pointeur à un mannequin de la méthode qui fait quelque chose de semblable à une affirmation.

Notez qu'une classe abstraite peut définir une mise en œuvre d'une fonction virtuelle pure, mais cette fonction ne peut être appelée avec un personnel qualifié-id syntaxe (ie., entièrement spécifiant la classe dans le nom de la méthode, similaire à l'appel d'une méthode de classe de base d'une classe dérivée). Ceci est fait afin de fournir un outil facile à utiliser par défaut de mise en œuvre, tout en exigeant qu'une classe dérivée de fournir un remplacement.

2voto

jheriko Points 2326

Vous pouvez recréer les fonctionnalités de fonctions virtuelles en C++ à l'aide de pointeurs de fonction en tant que membres d'une classe et les fonctions statiques comme les implémentations, ou à l'aide du pointeur de fonctions de membre et de membre des fonctions pour les implémentations. Il y a seulement de notation des avantages entre les deux méthodes... en fait, virtuel les appels de fonction sont juste une commodité de notation elles-mêmes. En fait, l'héritage est juste une commodité de notation... tout peut être mis en œuvre sans l'aide de la langue de fonctionnalités pour l'héritage. :)

Ci-dessous l'est de la merde non testé, probablement du code bogué, mais j'espère que démontre l'idée.

par exemple

class Foo
{
protected:
 void(*)(Foo*) MyFunc;
public:
 Foo() { MyFunc = 0; }
 void ReplciatedVirtualFunctionCall()
 {
  MyFunc(*this);
 }
...
};

class Bar : public Foo
{
private:
 static void impl1(Foo* f)
 {
  ...
 }
public:
 Bar() { MyFunc = impl1; }
...
};

class Baz : public Foo
{
private:
 static void impl2(Foo* f)
 {
  ...
 }
public:
 Baz() { MyFunc = impl2; }
...
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X