2017-05-12 5 views
3

J'ai une question concernant l'opérateur d'indice, la surcharge et l'héritage en C++. Je suis à peu près certain que si vous avez une classe parente avec plusieurs surcharges de fonctions, il est possible que l'enfant ne remplace qu'une seule des fonctions et hérite du reste. La même chose ne semble pas s'appliquer à l'opérateur d'indice. (je fait une mauvaise hypothèse, il est vraiment pas différent de toute autre fonction..) Considérez le code suivant:Règles d'héritage C++ pour l'opérateur d'indice

struct A {}; 
struct B {}; 

struct Parent 
{ 
    virtual ~Parent() {} 
    virtual int operator[](A index) { return -1; } 
    virtual int operator[](B index) { return -2; } 
}; 

struct Child : public Parent 
{ 
    virtual int operator[](B index) override { return -3; } 
}; 

int main() 
{ 
    // error: no match for 'operator[]' (operand types are 'Child' and 'A') 
    return Child()[A()]; 
} 

j'attendre pour qu'il puisse utiliser l'opérateur d'indexation du parent au lieu de provoquer une erreur. Est-il possible d'hériter de certains opérateurs d'indice surchargés du parent et de surcharger les autres? Sinon, est-il une meilleure solution que de le faire:

struct Child : public Parent 
{ 
    virtual int operator[](B index) override { return -3; } 
    // Force it to use the parent method 
    virtual int operator[](A index) override { return Parent::operator[](index); } 
}; 

Depuis que je hérite potentiellement des parents beaucoup d'endroits, et il est mauvais pour l'entretien d'avoir à spécifier manuellement des fonctions comme celle-ci. Merci pour vos idées.

+2

Il y a toujours 'using Parent :: operator []' mais vous devez toujours l'écrire dans chaque classe. –

+1

La résolution de surcharge s'arrête dès qu'elle trouve des candidats avec le nom souhaité. Donc, il verra 'Child :: operator [] (B)' et arrêtera de chercher des surcharges supplémentaires, donc il ne verra jamais une version qui prend un 'A'. Si vous utilisez 'Parent :: operator []' comme @JamesRoot le suggère, cela ajoutera toutes les surcharges dans la portée de 'Child' afin que les surcharges fonctionnent comme prévu. – 0x5453

+1

Qu'est-ce qui vous donne l'idée que ce problème est différent simplement parce que c'est l'opérateur d'indice? Modifiez votre code pour utiliser une fonction ordinaire appelée 'f' et vous rencontrerez la même erreur de compilation. –

Répondre

4

Évitez deux choses en C++:

  • mélange surcharge et dominante.
  • Fonctions virtuelles publiques (si ce n'est pas le destructeur).

Conservez vos opérateurs surchargés de classe de base non-virtuels et faites-les déléguer à des fonctions virtuelles privées avec des noms distincts.

Voici un exemple:

struct A {}; 
struct B {}; 

struct Parent 
{ 
    virtual ~Parent() {} 
    int operator[](A index) { return withA(index); } 
    int operator[](B index) { return withB(index); } 
private: 
    virtual int withA(A index) { return -1; } 
    virtual int withB(B index) { return -2; } 
}; 

struct Child : public Parent 
{ 
private: 
    virtual int withB(B index) override { return -3; } 
}; 

int main() 
{ 
    return Child()[A()]; 
} 

Cette approche, également connu sous le nom Non-Virtual Interface Idiom, représente une séparation bien des préoccupations entre les clients de la classe de base et les classes dérivées de implementors. Il résout également votre problème de compilation comme un effet secondaire.

+0

J'ai quitté le destructeur virtuel pour simplifier l'exemple, mais oui, techniquement il devrait être là (je l'ai ajouté à la question). C'est une idée valable, mais je vais aller avec l'idée de James Root. Merci. – Mark