Est-il possible en C ++ d'avoir une fonction membre qui est à la fois static
et virtual
? Apparemment, il n'y a pas de moyen simple de le faire (il static virtual member();
s'agit d'une erreur de compilation), mais y a-t-il au moins un moyen d'obtenir le même effet?
C'EST À DIRE:
struct Object
{
struct TypeInformation;
static virtual const TypeInformation &GetTypeInformation() const;
};
struct SomeObject : public Object
{
static virtual const TypeInformation &GetTypeInformation() const;
};
Il est logique d'utiliser à la GetTypeInformation()
fois sur une instance ( object->GetTypeInformation()
) et sur une classe ( SomeObject::GetTypeInformation()
), ce qui peut être utile pour les comparaisons et vital pour les modèles.
Le seul moyen auquel je puisse penser consiste à écrire deux fonctions / une fonction et une constante, par classe, ou à utiliser des macros.
D'autres solutions?
const
signature in a method marque lethis
pointeur implicite comme constant et ne peut pas être appliqué aux méthodes statiques car elles n'ont pas le paramètre implicite.Réponses:
Non, il n'y a aucun moyen de le faire, puisque que se passerait-il lorsque vous appeliez
Object::GetTypeInformation()
? Il ne peut pas savoir quelle version de classe dérivée appeler car aucun objet ne lui est associé.Vous devrez en faire une fonction virtuelle non statique pour fonctionner correctement; si vous souhaitez également pouvoir appeler la version d'une classe dérivée spécifique de manière non virtuelle sans instance d'objet, vous devrez également fournir une deuxième version statique non virtuelle redondante.
la source
Beaucoup disent que ce n'est pas possible, j'irais plus loin et je dirais que cela n'a pas de sens.
Un membre statique est quelque chose qui ne se rapporte à aucune instance, uniquement à la classe.
Un membre virtuel est quelque chose qui ne se rapporte directement à aucune classe, uniquement à une instance.
Ainsi, un membre virtuel statique serait quelque chose qui ne se rapporte à aucune instance ni à aucune classe.
la source
static virtual
méthode, mais une méthodestatic
purevirtual
est très significative dans une interface.static const string MyClassSillyAdditionalName
.J'ai rencontré ce problème l'autre jour: j'avais des classes pleines de méthodes statiques mais je voulais utiliser l'héritage et les méthodes virtuelles et réduire la répétition du code. Ma solution était:
Au lieu d'utiliser des méthodes statiques, utilisez un singleton avec des méthodes virtuelles.
En d'autres termes, chaque classe doit contenir une méthode statique que vous appelez pour obtenir un pointeur vers une seule instance partagée de la classe. Vous pouvez rendre les vrais constructeurs privés ou protégés afin que le code extérieur ne puisse pas en abuser en créant des instances supplémentaires.
En pratique, l'utilisation d'un singleton ressemble beaucoup à l'utilisation de méthodes statiques, sauf que vous pouvez tirer parti de l'héritage et des méthodes virtuelles.
la source
C'est possible!
Mais ce qui est exactement possible, limitons-nous. Les gens veulent souvent une sorte de "fonction virtuelle statique" à cause de la duplication du code nécessaire pour pouvoir appeler la même fonction via l'appel statique "SomeDerivedClass :: myfunction ()" et l'appel polymorphe "base_class_pointer-> myfunction ()". La méthode "légale" pour autoriser une telle fonctionnalité est la duplication des définitions de fonction:
Et si la classe de base a un grand nombre de fonctions statiques et que la classe dérivée doit les remplacer toutes et que l'on oublie de fournir une définition de duplication pour la fonction virtuelle. Bien, nous aurons une erreur étrange pendant l' exécution qui est difficile à localiser. Parce que la duplication de code est une mauvaise chose. Ce qui suit tente de résoudre ce problème (et je veux dire à l'avance qu'il est complètement sûr de type et ne contient aucune magie noire comme celle de typeid ou dynamic_cast :)
Donc, nous voulons fournir une seule définition de getTypeInformation () par classe dérivée et il est évident qu'il doit s'agir d'une définition de staticfonction car il n'est pas possible d'appeler "SomeDerivedClass :: getTypeInformation ()" si getTypeInformation () est virtuel. Comment pouvons-nous appeler une fonction statique d'une classe dérivée via un pointeur vers la classe de base? Ce n'est pas possible avec vtable car vtable stocke des pointeurs uniquement vers des fonctions virtuelles et comme nous avons décidé de ne pas utiliser de fonctions virtuelles, nous ne pouvons pas modifier vtable à notre avantage. Ensuite, pour pouvoir accéder à la fonction statique d'une classe dérivée via un pointeur vers la classe de base, nous devons stocker en quelque sorte le type d'un objet dans sa classe de base. Une approche consiste à créer un modèle de classe de base en utilisant un "modèle de modèle curieusement récurrent" mais ce n'est pas approprié ici et nous utiliserons une technique appelée "effacement de type":
Maintenant, nous pouvons stocker le type d'un objet dans la classe de base "Object" avec une variable "keeper":
Dans un gardien de classe dérivé doit être initialisé pendant la construction:
Ajoutons du sucre syntaxique:
Maintenant, les déclarations des descendants ressemblent à:
usage:
Avantages:
Désavantages:
Questions ouvertes:
1) il existe différents noms pour les fonctions statiques et virtuelles comment résoudre l'ambiguïté ici?
2) comment appeler implicitement OVERRIDE_STATIC_FUNCTIONS à l'intérieur de chaque constructeur?
la source
Bien qu'Alsk ait déjà donné une réponse assez détaillée, j'aimerais ajouter une alternative, car je pense que sa mise en œuvre améliorée est trop compliquée.
Nous commençons avec une classe de base abstraite, qui fournit l'interface pour tous les types d'objets:
Maintenant, nous avons besoin d'une mise en œuvre réelle. Mais pour éviter d'avoir à écrire à la fois les méthodes statiques et virtuelles, nous ferons en sorte que nos classes d'objets réelles héritent des méthodes virtuelles. Cela ne fonctionne évidemment que si la classe de base sait comment accéder à la fonction membre statique. Nous devons donc utiliser un modèle et lui passer le nom de la classe des objets réels:
Enfin, nous devons implémenter notre (nos) objet (s) réel (s). Ici, nous avons seulement besoin d'implémenter la fonction membre statique, les fonctions membres virtuelles seront héritées de la classe de modèle ObjectImpl, instanciées avec le nom de la classe dérivée, afin qu'elle accède à ses membres statiques.
Ajoutons du code à tester:
Addendum (12 janvier 2019):
Au lieu d'utiliser la fonction GetClassNameStatic (), vous pouvez également définir le nom de la classe en tant que membre statique, même "inline", qui fonctionne depuis C ++ 11 (ne soyez pas effrayé par tous les modificateurs :)):
la source
C'est possible. Faites deux fonctions: statique et virtuelle
la source
Non, ce n'est pas possible, car les fonctions membres statiques n'ont pas de
this
pointeur. Et les membres statiques (fonctions et variables) ne sont pas vraiment des membres de classe en soi. Ils sont simplement appelés parClassName::member
et adhèrent aux spécificateurs d'accès aux classes. Leur stockage est défini quelque part en dehors de la classe; le stockage n'est pas créé à chaque fois que vous instanciez un objet de la classe. Les pointeurs vers les membres de classe sont spéciaux dans la sémantique et la syntaxe. Un pointeur vers un membre statique est un pointeur normal à tous égards.les fonctions virtuelles d'une classe ont besoin du
this
pointeur et sont très couplées à la classe, elles ne peuvent donc pas être statiques.la source
this
pointeur. les fonctions statiques ne sont pas spécifiques à une instance et n'en auraient pas besoin. Donc - ce n'est pas une raison pour laquelle les membres statiques virtuels sont impossibles.Eh bien, une réponse assez tardive, mais il est possible d'utiliser le modèle de modèle curieusement récurrent. Cet article de wikipedia contient les informations dont vous avez besoin et l'exemple sous polymorphisme statique est ce qui vous est demandé.
la source
Je pense que ce que vous essayez de faire peut être fait grâce à des modèles. J'essaye de lire entre les lignes ici. Ce que vous essayez de faire est d'appeler une méthode à partir d'un code, où elle appelle une version dérivée mais l'appelant ne spécifie pas quelle classe. Exemple:
Vous voulez que Try () appelle la version Bar de M sans spécifier Bar. La façon dont vous faites cela pour la statique est d'utiliser un modèle. Alors changez-le comme ceci:
la source
Non, la fonction membre statique ne peut pas être virtuelle. Car le concept virtuel est résolu au moment de l'exécution à l'aide de vptr, et vptr n'est pas un membre statique d'une classe. ne soyez pas virtuel.
la source
Ce n'est pas possible, mais c'est juste parce qu'une omission. Ce n'est pas quelque chose qui «n'a aucun sens» comme beaucoup de gens semblent le prétendre. Pour être clair, je parle de quelque chose comme ça:
C'est quelque chose qui pourrait être implémenté à 100% (ce n'est tout simplement pas le cas), et je dirais quelque chose d'utile.
Considérez le fonctionnement des fonctions virtuelles normales. Supprimez les
static
s et ajoutez d'autres éléments et nous avons:Cela fonctionne très bien et ce qui se passe, c'est que le compilateur crée deux tables, appelées VTables, et attribue des indices aux fonctions virtuelles comme celle-ci
Ensuite, chaque classe avec des fonctions virtuelles est augmentée avec un autre champ qui pointe vers sa VTable, de sorte que le compilateur les change fondamentalement pour être comme ceci:
Alors que se passe-t-il réellement lorsque vous appelez
b->sayMyName()
? Fondamentalement ceci:(Le premier paramètre devient
this
.)Ok, alors comment cela fonctionnerait-il avec des fonctions virtuelles statiques? Quelle est la différence entre les fonctions membres statiques et non statiques? La seule différence est que ces derniers reçoivent un
this
pointeur.Nous pouvons faire exactement la même chose avec les fonctions virtuelles statiques - il suffit de supprimer le
this
pointeur.Cela pourrait alors prendre en charge les deux syntaxes:
Alors ignorez tous les opposants. Il ne du sens. Pourquoi n'est-il pas pris en charge alors? Je pense que c'est parce que cela a très peu d'avantages et pourrait même être un peu déroutant.
Le seul avantage technique par rapport à une fonction virtuelle normale est que vous n'avez pas besoin de passer
this
à la fonction, mais je ne pense pas que cela ferait une différence mesurable sur les performances.Cela signifie que vous n'avez pas de fonction statique et non statique distincte pour les cas où vous avez une instance, et lorsque vous n'avez pas d'instance, mais il peut également être déroutant que ce soit vraiment "virtuel" lorsque vous utilisez l'appel d'instance.
la source
Non, ce n'est pas possible, car les membres statiques sont liés au moment de la compilation, tandis que les membres virtuels sont liés au moment de l'exécution.
la source
Premièrement, les réponses sont correctes que ce que l'OP demande est une contradiction dans les termes: les méthodes virtuelles dépendent du type d'exécution d'une instance; Les fonctions statiques ne dépendent pas spécifiquement d'une instance - juste d'un type. Cela dit, il est logique que les fonctions statiques retournent quelque chose de spécifique à un type. Par exemple, j'avais une famille de classes MouseTool pour le modèle State et j'ai commencé à avoir chacune une fonction statique renvoyant le modificateur de clavier qui allait avec; J'ai utilisé ces fonctions statiques dans la fonction d'usine qui a créé l'instance MouseTool correcte. Cette fonction a vérifié l'état de la souris par rapport à MouseToolA :: keyboardModifier (), MouseToolB :: keyboardModifier (), etc., puis a instancié celui qui convient. Bien sûr, plus tard, je voulais vérifier si l'état était correct, donc je voulais écrire quelque chose comme "
Donc, si vous le souhaitez, vous voudrez peut-être revoir votre solution. Pourtant, je comprends le désir d'avoir des méthodes statiques, puis de les appeler dynamiquement en fonction du type dynamique d'une instance. Je pense que le modèle de visiteur peut vous donner ce que vous voulez. Cela vous donne ce que vous voulez. C'est un peu de code supplémentaire, mais cela pourrait être utile pour d'autres visiteurs.
Voir: http://en.wikipedia.org/wiki/Visitor_pattern pour le contexte.
Puis pour chaque objet concret:
puis définissez le visiteur de base:
Puis le visiteur concret qui sélectionne la fonction statique appropriée:
enfin, utilisez-le:
Remarques:
Si vous souhaitez éviter les erreurs de copier-coller où l'une de vos méthodes de visite appelle la mauvaise fonction statique, vous pouvez utiliser une fonction d'assistance basée sur un modèle (qui ne peut pas elle-même être virtuelle) pour votre visiteur avec un modèle comme celui-ci:
la source
Foo foo; ... foo::bar();
au lieu deFoo::bar();
). Ce n'est pas différent,decltype(foo)::bar();
mais ce serait encore une fois lié statiquement. L'approche du visiteur semble être un moyen raisonnable d'obtenir ce comportement sans simplement faire de la méthode statique une méthode virtuelle const.Avec c ++, vous pouvez utiliser l'héritage statique avec la méthode crt. Pour l'exemple, il est largement utilisé sur les modèles de fenêtres atl & wtl.
Voir https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Pour être simple, vous avez une classe qui est basée sur elle-même comme class myclass: public myancestor. À partir de ce point, la classe myancestor peut désormais appeler votre fonction statique T :: YourImpl.
la source
Peut-être que vous pouvez essayer ma solution ci-dessous:
la source
Base::mSelf
fait référence à l'instance la plus récemment construite de toute classe dérivée, même si cette instance a été détruite . doncclass D1 : public Base ...; class D2 : public Base ...; ...; D1* pd1 = new D1(); D2* pd2 = new D2(); pd1->MyStaticFun(); /* calls D2::MyVirtualFun() */ delete pd2; pd1->MyStaticFun(); /* calls via deleted pd2 */
ce qui n'est PAS ce que l'on veut.Comme d'autres l'ont dit, il y a 2 informations importantes:
this
pointeur lors d'un appel de fonction statique etthis
pointeur pointe vers la structure où la table virtuelle, ou thunk, est utilisée pour rechercher la méthode d'exécution à appeler.Une fonction statique est déterminée au moment de la compilation.
J'ai montré cet exemple de code dans les membres statiques C ++ en classe ; cela montre que vous pouvez appeler une méthode statique avec un pointeur nul:
la source
p < null
,p >= null
etc., sont tous non définis également.