web-dev-qa-db-fra.com

c ++ surchargé alerte de fonction virtuelle par clang?

clang émet un avertissement lors de la compilation du code suivant:

struct Base
{
    virtual void * get(char* e);
//    virtual void * get(char* e, int index);
};

struct Derived: public Base {
    virtual void * get(char* e, int index);
};

L'avertissement est:

warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]

(cet avertissement doit être activé bien sûr).

Je ne comprends pas pourquoi. Notez que le fait de ne pas commenter la même déclaration dans Base ferme l'avertissement. D'après ce que je comprends, les deux fonctions get () ayant des signatures différentes, il ne peut y avoir de dissimulation.

Clang a-t-il raison? Pourquoi?

Notez que ceci est sur MacOS X, exécutant une version récente de Xcode.

clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)

Mise à jour: même comportement avec Xcode 4.6.3.

64
Jean-Denis Muys

Cet avertissement est là pour empêcher le masquage accidentel de surcharges lorsque le remplacement est prévu. Prenons un exemple légèrement différent:

struct chart; // let's pretend this exists
struct Base
{
    virtual void* get(char* e);
};

struct Derived: public Base {
    virtual void* get(chart* e); // typo, we wanted to override the same function
};

Comme il s'agit d'un avertissement, cela ne signifie pas nécessairement que c'est une erreur, mais cela peut en indiquer une. Habituellement, de tels avertissements ont un moyen de les arrêter en étant plus explicites et en laissant le compilateur savoir que vous avez bien voulu ce que vous avez écrit. Je crois que dans ce cas, vous pouvez faire ce qui suit:

struct Derived: public Base {
    using Base::get; // tell the compiler we want both the get from Base and ours
    virtual void * get(char* e, int index);
};
107

R. Martinho Fernandes La solution est parfaitement valable si vous voulez réellement utiliser la méthode get() en prenant un seul argument char * dans Derived scope.

En fait, dans l'extrait que vous avez fourni, les méthodes virtuelles ne sont pas nécessaires (car Base et Derived ne partagent aucune méthode avec la même signature).

En supposant qu'il y ait réellement un besoin de polymorphisme, le comportement masquant pourrait néanmoins être ce qui est prévu. Dans ce cas, il est possible de désactiver localement l'avertissement de Clang, avec le pragma suivant:

#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
    // Member declaration raising the warning.
#pragma clang diagnostic pop
22
Ad N

Une autre façon de désactiver l'avertissement en gardant l'interface publique publique de struct est la suivante:

struct Derived: public Base
{
    virtual void * get(char* e, int index);
private:
    using Base::get;
};

Ceci interdit à un consommateur de Derived d'appeler Derived::get(char* e) tout en désactivant l'avertissement:

Derived der;
der.get("", 0); //Allowed
der.get("");    //Compilation error
21
Pedro

Avertissement signifie qu'il n'y aura pas de fonction void * get (char * e) dans l'étendue de la classe Derived, car elle sera masquée par une autre méthode portant le même nom. Le compilateur ne cherchera pas de fonction dans les classes de base si la classe dérivée a au moins une méthode avec le nom spécifié, même si elle a d'autres arguments.

Cet exemple de code ne compilera pas:

class A
{
public:
    virtual void Foo() {}
};

class B : public A
{
public:
    virtual void Foo(int a) {}
};


int main()
{
    B b;
    b.Foo();
    return 0;
}
12
WormholeWizard