web-dev-qa-db-fra.com

Fonction statique de surcharge C ++ avec fonction non statique

Je voudrais imprimer deux choses différentes selon que la fonction est appelée statiquement avec Foo::print() ou à partir d'une instance de Foo foo; foo.print();

EDIT: Voici une définition de classe qui ne fonctionne certainement pas, comme l'ont déjà répondu quelques personnes.

class Foo {
    string bla;
    Foo() { bla = "nonstatic"; }

    void print() { cout << bla << endl; }
    static void print() { cout << "static" << endl; }
};

Cependant, existe-t-il un bon moyen d'obtenir cet effet? Fondamentalement, je voudrais faire:

if(this is a static call)
    do one thing
else
    do another thing

Formulé d'une autre manière, je sais PHP peut vérifier si le *this variable est définie ou non pour déterminer si la fonction est appelée statiquement. C++ a-t-il les mêmes capacités?

37
Alan Turing

Non, c'est directement interdit par la norme:

ISO 14882: 2003 C++ Standard 13.1/2 - Déclarations surchargeables

Certaines déclarations de fonctions ne peuvent pas être surchargées:

  • Les déclarations de fonction qui ne diffèrent que par le type de retour ne peuvent pas être surchargées.
  • Les déclarations de fonctions membres portant le même nom et les mêmes types de paramètres ne peuvent pas être surchargées si l'une d'entre elles est une déclaration de fonction membre static (9.4).

...

[Exemple:

class X {
    static void f();
    void f();                // ill-formed
    void f() const;          // ill-formed
    void f() const volatile; // ill-formed
    void g();
    void g() const;          // OK: no static g
    void g() const volatile; // OK: no static g
};

- fin exemple]

...

De plus, ce serait de toute façon ambigu car il est possible d'appeler des fonctions statiques sur des instances:

ISO 14882: 2003 C++ Standard 9.4/2 - Membres statiques

Un membre statique s de la classe X peut être appelé à l'aide de l'expression qualifié-id 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 static member. Un membre static peut être référencé à l'aide de la syntaxe d'accès aux membres de la classe, auquel cas le object-expression Est évalué. [Exemple:

class process {
public:
        static void reschedule();
}
process& g();
void f()
{
        process::reschedule(); // OK: no object necessary
        g().reschedule();      // g() is called
}

- fin exemple]

...

Il y aurait donc une ambiguïté avec ce que vous avez:

class Foo
{
public:
    string bla;
    Foo() { bla = "nonstatic"; }
    void print() { cout << bla << endl; }
    static void print() { cout << "static" << endl; }
};

int main()
{
    Foo f;
    // Call the static or non-static member function?
    // C++ standard 9.4/2 says that static member
    // functions are callable via this syntax. But
    // since there's also a non-static function named
    // "print()", it is ambiguous.
    f.print();
}

Pour répondre à votre question de savoir si vous pouvez vérifier à quelle instance une fonction membre est appelée, il existe le mot clé this. Le mot clé this pointe vers l'objet pour lequel la fonction a été invoquée. Cependant, le mot clé this pointera toujours vers un objet, c'est-à-dire qu'il ne sera jamais NULL. Il n'est donc pas possible de vérifier si une fonction est appelée statiquement ou non à la PHP.

ISO 14882: 2003 C++ Standard 9.3.2/1 - Le pointeur this

Dans le corps d'une fonction membre non statique (9.3), le mot clé this est une expression non lvalue dont la valeur est l'adresse de l'objet pour lequel la fonction est appelée.

57
In silico

Ce n'est certainement pas permis. Je ne vois aucun moyen propre d'y parvenir. Quel est exactement le problème que vous souhaitez résoudre de cette façon?

2
Janick Bernet

Vous ne pouvez pas faire exactement cela, voir réponse de Silico .

Mais vous pouvez faire en sorte que Foo::print() et Foo foo; print(foo); fassent des choses différentes. (Définissez void print(Foo& foo) dans le même espace de nom que class Foo, il sera trouvé par ADL).

En tout cas, ce n'est pas une bonne idée. Vous avez deux fonctions très similaires dans leur nom qui font des choses complètement différentes, ce qui viole les bons principes de conception.

1
Ben Voigt

La réponse est non, car vous ne pouvez pas surcharger en fonction d'un type de retour.

Vous pouvez certainement avoir des méthodes statiques dans une classe, mais vous ne pouvez pas avoir:

static void foo();
void foo();

Parce qu'ils ont la même signature de méthode.

EDIT: J'ai vu votre commentaire dire pourquoi vous vouliez faire cela, et que vous vouliez accéder aux variables membres. Vous devez faire ceci:

static void print(Foo f);
void print();
....
static void Foo::print(Foo f)
{
    int a = f.a;
    // do something with a
}

(Ou créez des getters et setters dans Foo, etc., mais c'est l'idée générale)

1
Brian Roach