2008-11-28 3 views
30

Voici un petit programme de test:C++ appel de méthode Membre statique sur instance de la classe

Sur VS2008 + SP1 (VC9) il compile bien: "IT Test" la console juste afficher.

Pour autant que je sache, les méthodes membres statiques ne doivent pas être appelé sur l'objet instancié.

  1. Je me trompe? Ce code est-il correct du point de vue standard?
  2. Si c'est correct, pourquoi? Je ne peux pas trouver pourquoi il serait autorisé, ou peut-être que c'est pour aider à utiliser la méthode "statique ou non" dans les modèles?
+0

Quelle est la mvc t ag? – Kiril

+0

Correction: J'ai peut-être mixé avec msvc à l'époque, je pensais que ça pourrait être un problème de compilateur. – Klaim

Répondre

54

La norme qu'il est pas nécessaire d'appeler la méthode par une instance, cela ne signifie pas que vous ne pouvez pas le faire. Il y a même un exemple où il est utilisé:

C++ 03, 9.4 membres statiques

Un membre statique de la classe X peut être visé à l'aide de l'expression id qualifié X :: s ; il est pas nécessaire d'utiliser l'accès membre de la classe syntaxe (5.2.5) pour se référer à un membre statique. Un élément statique peut être nommé en utilisant la syntaxe d'accès au membre de la classe, dans lequel cas le -expression d'objet est évaluée .

class process { 
public: 
    static void reschedule(); 
}; 

process& g(); 

void f() 
{ 
    process::reschedule(); // OK: no object necessary    
    g().reschedule(); // g() is called 
} 
+0

Wow, je n'ai jamais su cela. Je suppose que la fonction qui est appelée est basée uniquement sur le type de compilation (pas sur le type d'exécution) de l'expression? –

+0

@SethCarnegie: Oui, il utilise le type de temps de compilation de l'objet (ou une référence de celui-ci), vous ne pouvez pas obtenir l'envoi dynamique aux méthodes membres statiques. –

+0

C'est dommage. +1 –

2

méthodes statiques peuvent être appelées également d'utiliser un objet de la classe, tout comme il peut être fait en Java. Néanmoins, vous ne devriez pas faire cela. Utilisez l'opérateur portée comme Test::DoCrash(); Peut-être que vous pensez de namespaces:

namespace Test { 
    void DoCrash() { 
     std::cout << "Crashed!!" << std::endl; 
    } 
}; 

qui ne peut être appelé par Test::DoCrash(); à l'extérieur que l'espace de noms si la fonction n'est pas importée en utilisant explicitement using directive/declaration dans le cadre de l'appelant.

+2

Oui, je sais que je devrais faire ceci, c'est pourquoi je demande pourquoi l'autre manière (appelant comme un membre) est permise/pas interdite. :) – Klaim

8

fonctions statiques ont besoin d'un objet instancié Indifférent Fume pour être appelé, si

k.DoCrash(); 

se comporte exactement les mêmes que

Test::DoCrash(); 

en utilisant l'opérateur de résolution de portée (::) pour déterminer la fonction statique à l'intérieur de la classe.

Notez que dans les deux cas, le compilateur mis le pointeur Indifférent Fume this dans la pile puisque la fonction statique n'a pas besoin.

+1

Je préfère dire _pass 'this' en tant que paramètre_ au lieu de _put dans la pile_. La manière réelle est soumise à la convention d'appel de la plate-forme particulière. Cependant, +1 pour mentionner cette fonctionnalité des méthodes statiques. – Melebius

+0

Il y a une différence: dans 'k.DoCrash()', le préfixe 'k' est évalué. Si 'k' est juste un nom d'objet, cela n'a probablement pas d'importance, mais ce pourrait être un appel de fonction ou une autre expression avec des effets secondaires:' func(). DoCrash() ' –

3

2) Si c'est correct, pourquoi? Je ne peux pas trouver pourquoi il serait autorisé, ou peut-être que c'est pour aider à utiliser la méthode "statique ou non" dans les modèles?

Il est potentiellement utile dans plusieurs scénarios:

  • [la « méthode « statique ou non » dans les modèles » vous suggère:] quand de nombreux types auraient été spécifiés à un modèle, et le template veut alors appeler le membre: les types fournissant une fonction statique peuvent être appelés en utilisant la même notation qu'une fonction membre - le premier peut être plus efficace (pas de this pointeur pour passer/lier), tandis que le second permet polymorphique (virtual) envoi et utilisation des données de membre

  • réduisant au minimum la maintenance du code

    • si une fonction évolue d'avoir besoin de données spécifiques à l'instance de ne pas en avoir besoin - et est donc fait static pour permettre l'utilisation de l'instance facile et sans empêcher l'utilisation accidentelle de données d'instance - tous les points d'utilisation des clients existants ne doivent pas nécessairement être mis à jour laborieusement

    • si changé de type l'invocation var.f() continue d'utiliser la fonction du type var, alors que Type::f() peut avoir besoin de correction manuelle

  • lorsque vous avez une expression ou un appel fonction renvoyant une valeur et que vous voulez invoquer le (potentiellement ou toujours) fonction static, la notation . peut empêcher que vous ayez besoin d'utiliser decltype ou un modèle de soutien pour obtenir l'accès au le type, juste pour que vous pouvez utiliser la notation ::

  • parfois le nom de la variable est juste beaucoup plus courte, plus pratique, ou le nom d'une manière plus auto-documenté

+1

Sur le compilateur MSVC 2013 au moins, appelant méthodes statiques via une instance fonctionne, mais génère un avertissement du compilateur sur une variable non référencée si la variable n'est pas utilisée pour autre chose que d'appeler une méthode statique. – abelenky