Question

Pourquoi, par exemple, n’existe-t-il pas de support linguistique pour examiner une table virtuelle? Pourquoi ne puis-je pas remplacer une fonction membre par une nouvelle? J’ai le sentiment qu’il existe des moyens de tirer parti de ces fonctionnalités.

Existe-t-il d'autres langues qui me permettent de faire de telles choses?

Était-ce utile?

La solution

La raison principale est que conserver vtable en tant que détail d'implémentation permet à toute implémentation concrète de l'optimiser à sa guise. cela signifie qu'il peut par exemple Couper ou même éliminer vtable si cela peut prouver qu'il n'y a pas d'appels virtuels pour une méthode donnée (ou toutes les méthodes). Ou bien, il peut remplacer une répartition vtable par une vérification de type if-else si, par exemple, il voit qu'il n'y a que peu d'alternatives (ceci peut être avantageux car la prédiction de branche fonctionnera dans ce cas, mais pas avec vtables, et aussi parce que les branches if-else peuvent alors être en ligne). Il peut réorganiser les méthodes dans vtable de telle sorte que les méthodes les plus couramment appelées viennent plus tôt, ou que celles qui sont communément appelées l'une après l'autre remplissent les emplacements adjacents dans vtable pour tirer parti de la mise en cache. Et ainsi de suite. Bien entendu, toutes ces implémentations rendraient également la mise en page vtable totalement imprévisible, et donc inutile, si elle était exposée (par la spécification du langage) à la mise en œuvre.

De même, les vtables ne sont pas aussi simples qu’elles paraissent être. Par exemple, les compilateurs doivent souvent générer des thunks pour corriger ce pointeur pour des éléments tels que l'héritage virtuel ou l'héritage multiple combiné à des types de retour covariants. C’est là encore quelque chose qui n’a pas de "méthode unique". pour le faire (c’est pourquoi différents compilateurs le font différemment), et sa standardisation nécessiterait effectivement de s’installer sur un mode particulier.

Cela dit, "Vtable Switching" est une technique potentiellement utile si elle est exposée en tant que construction de niveau supérieur (pour que des optimisations soient toujours possibles). Pour un exemple, voir UnrealScript, qui permet de définir plusieurs états pour une classe (une par défaut, une autre). named) et substituer certaines méthodes dans les états nommés. Les classes dérivées peuvent remplacer plusieurs méthodes dans des états existants ou ajouter leurs propres états et les remplacer. De plus, les états peuvent étendre d'autres états (ainsi, si une méthode n'est pas remplacée pour un état particulier, elle retourne à l'état "parent", et ainsi de suite jusqu'à ce que la chaîne atteigne l'état par défaut). Pour la modélisation d'acteur (qui sont essentiellement des jeux), cela a beaucoup de sens, c'est pourquoi UnrealScript l'a. Et le mécanisme évident de mise en œuvre efficace pour tout cela est la commutation de vtable, chaque état ayant une vtable distincte.

Autres conseils

Parce que c'est un détail d'implémentation du compilateur. Cette implémentation peut changer et tout code qui en dépend serait au mieux fragile.

C ++ est un langage dans lequel vous ne payez jamais ce que vous n'utilisez pas. Ce type de support d'exécution irait à l'encontre de cette philosophie.

Il existe de nombreuses langues (du côté le plus dynamique du spectre) qui supportent cela.

Parce que cela ne doit pas nécessairement être implémenté en tant que VTable , bien que ce soit généralement le cas. En bref, VTable en C ++ n’existe pas.

JavaScript, Python et Ruby peuvent tous le faire. Dans ces langues, les définitions de classe et d'instance peuvent être modifiées au moment de l'exécution. En résumé, chaque objet et type est un dictionnaire de variables membres et de méthodes pouvant être examinées et mises à jour.

Cela n’est pas possible en C ++, car il faudrait pouvoir réécrire le code binaire généré, ce qui peut entraîner un coût de performances substantiel.

Les tables de données n'existent que dans certaines circonstances dans certains compilateurs (c’est-à-dire qu’elles ne sont pas spécifiées dans la norme mais dans le détail de la mise en œuvre). Même lorsqu'elles existent, elles ne surviennent que lorsque vous avez des fonctions virtuelles et que vous avez besoin de l'indirection pour mettre en œuvre le polymorphisme. Lorsque cela n’est pas nécessaire, ils peuvent être optimisés, ce qui évite le surdébit indirectionnel de l’appel.

Malheureusement (ou autrement, selon votre point de vue sur le sujet ;-), C ++ n’a pas été conçu pour prendre en charge la correction de singe. Dans certains cas (COM, par exemple), la vtable fait partie de l’implémentation et vous pourrez peut-être fouiller dans les coulisses. Cependant, cela ne serait jamais supporté ou portable.

Je pense que vous pouvez faire des choses comme ça dans des langages dynamiques comme Python:

>>> class X():
...     def bar(self): print "bar"
...     
>>> x = X()
>>> x.bar()
bar
>>> def foo(x): print "foo"
... 
>>> X.bar = foo
>>> x.bar()
foo

La différence avec un langage statique tel que C ++ réside dans le fait que l'interprète recherche tous les noms au moment de l'exécution et décide ensuite quoi faire.

En C ++, il existe probablement d'autres solutions pour remplacer "une fonction membre par une autre". problème, dont le plus simple pourrait utiliser des pointeurs de fonction:

#include <iostream>

class X;
typedef void (*foo_func)(const X&);

void foo(const X&) { std::cout << "foo\n"; }
void bar(const X&) { std::cout << "bar\n"; }

class X
{
    foo_func f;
public:
    X(): f(foo) {}
    void foobar() { f(*this); }
    void switch_function(foo_func new_foo) { f = new_foo; }
};

int main()
{
    X x;
    x.foobar();
    x.switch_function(bar);
    x.foobar();
}

(foo et bar n'utilisent pas l'argument X &, dans cet exemple, similaire à l'exemple Python)

Je travaille sur un langage compilé de manière statique qui expose la vtable et croyez-moi, il s'agit d'un peu de cheveux à exposer.

  • Tout ce que vous pouvez faire en C ++, vous pouvez le faire en C droit avec un peu de graisse pour coude.
  • Tout programme C modeste et raisonnable doit compiler en C ++.

Peut-être que ce que vous voulez, c'est implémenter vos propres vtables sans utiliser la fonctionnalité intégrée de C ++. Vous aurez beaucoup de plaisir avec les fonctions pointeur vers membre (ptmf)!

Vous aurez du mal à trouver un langage compilé avec l'introspection de vtable car la demande est faible et sa mise en œuvre difficile. Pour les langages interprétés, la situation est inversée.

  

Existe-t-il d'autres langues?   là qui me permettent de faire une telle   des choses?

Objective-C (et Objective-C ++ également) permet le remplacement à l'exécution de méthodes déjà compilées. C'est soit la meilleure combinaison de techniques statiques et dynamiques, soit la pire, en fonction de qui vous demandez.

Comme d'autres l'ont fait remarquer, il n'y a pas de concept de "vtable". dans la norme C ++, car il s’agit simplement d’une technique de mise en œuvre quasi universelle, un peu comme le nom mangling.

Si vous cherchez à pouvoir redéfinir des fonctions à la volée dans un langage compilé, Common Lisp pourrait vous intéresser. Il doit y en avoir d'autres, mais les seuls autres langages auxquels je puisse penser ont un héritage et des fonctions statiques ou sont interprétés à un coût élevé en performances.

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