web-dev-qa-db-fra.com

Appel de méthode membre statique C ++ sur une instance de classe

Voici un petit programme de test:

#include <iostream>

class Test
{
public:
    static void DoCrash(){ std::cout<< "TEST IT!"<< std::endl; }
};

int main()
{
    Test k;
    k.DoCrash(); // calling a static method like a member method...

    std::system("pause");

    return 0;
}

Sur VS2008 + SP1 (vc9) ça compile très bien: la console affiche juste "TEST IT!".

Pour autant que je sache, les méthodes membres statiques ne doivent pas être appelées sur des objets instanciés.

  1. Ai-je tort? Ce code est-il correct du point de vue standard?
  2. Si c'est correct, pourquoi? Je ne trouve pas pourquoi cela serait autorisé, ou peut-être est-ce pour aider à utiliser la méthode "statique ou non" dans les modèles?
38
Klaim

La norme stipule qu'il n'est pas nécessaire d'appeler la méthode via 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 s de la classe X peut être référencé en utilisant l'expression d'ID qualifié X :: s; il n'est pas nécessaire d'utiliser la syntaxe d'accès aux membres de classe (5.2.5) pour faire référence à un membre statique. Un membre statique peut être référencé à l'aide de la syntaxe d'accès aux membres de la classe, auquel cas l'expression-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
}

Les fonctions statiques n'ont pas besoin d'un objet instancié pour être appelées, donc

k.DoCrash();

se comporte exactement comme

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 ne place pas le pointeur this dans la pile car la fonction statique n'en a pas besoin.

11
jab

2) Si c'est correct, pourquoi? Je ne trouve pas pourquoi cela serait autorisé, ou peut-être est-ce 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érez:] lorsque de nombreux types auraient pu être spécifiés dans un modèle, et que le modèle souhaite ensuite invoquer le membre: les types fournissant une fonction statique peut être appelée en utilisant la même notation qu'une fonction membre - la première peut être plus efficace (pas de pointeur this pour passer/lier), tandis que la seconde permet la répartition polymorphe (virtual) et l'utilisation de données des membres

  • minimiser la maintenance du code

    • si une fonction passe du besoin de données spécifiques à l'instance au fait de ne pas en avoir besoin - et est donc créée static pour permettre une utilisation facile sans instance et empêcher une utilisation accidentelle des données d'instance - tous les points d'utilisation du client existant ne le font pas doivent être mis à jour avec soin

    • si le type a changé, l'invocation de var.f() continue d'utiliser la fonction de type var, tandis que Type::f() peut nécessiter une correction manuelle

  • lorsque vous avez une expression ou un appel de fonction renvoyant une valeur et que vous souhaitez appeler la fonction (potentiellement ou toujours) static, la fonction . la notation peut vous empêcher d'utiliser decltype ou un modèle de prise en charge pour accéder au type, juste pour pouvoir utiliser le :: notation

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

3
Tony Delroy

les méthodes statiques peuvent être appelées également en utilisant un objet de la classe, tout comme cela peut être fait en Java. Néanmoins, vous ne devriez pas faire cela. Utilisez l'opérateur scope comme Test::DoCrash(); Vous pensez peut-être aux espaces de noms:

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

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

2