Méthode de surcharge dans la classe de base, avec la variable membre par défaut

J’ai une structure de classe comme suit:

class Base { public: void setDefault( uint8_t my_default ) { m_default = my_default; } void method( uint8_t * subject ) { method( subject, m_default ); } virtual void method( uint8_t * subject, uint8_t parameter ) =0; protected: uint8_t m_default; }; class Derived1 : public Base { public: void method ( uint8_t * subject, uint8_t parameter ) { /* do something to subject */ } }; class Derived2 : public Base { public: void method ( uint8_t * subject, uint8_t parameter ) { /* do something different to subject */ } }; 

Je veux pouvoir appeler method( ... ) sur n’importe quelle instance d’une classe dérivée de Base , qui appellera la méthode définie dans la classe dérivée en utilisant la variable membre comme paramètre par défaut.

D’après ce que j’ai lu ailleurs sur Stack Overflow, le remplacement doit avoir la même signature, c’est pourquoi il ne comstack pas.

Y a-t-il des ambiguïtés potentielles avec cette approche?

Je peux penser à deux façons de contourner ce problème:

  1. déclarer une method( void ) par défaut method( void ) pour chaque classe dérivée, mais cela ne semble pas très sec
  2. utilisez un nom différent pour la méthode par défaut (par exemple, defaultMethod( uint8_t * subject ) ), mais j’estime que cela rend ma classe moins intuitive

Y at-il une meilleure façon de contourner cela?


Voici un exemple complet, qui ne comstackra pas (Arduino IDE 1.7.9):

 class Base { public: void setDefault( uint8_t my_default ) { m_default = my_default; } void method( uint8_t * subject ) { method( subject, m_default ); } virtual void method( uint8_t * subject, uint8_t parameter ) =0; protected: uint8_t m_default; }; class Derived1 : public Base { public: void method ( uint8_t * subject, uint8_t parameter ) { *subject += parameter; } }; class Derived2 : public Base { public: void method ( uint8_t * subject, uint8_t parameter ) { *subject *= parameter; } }; Derived1 derived1; Derived2 derived2; uint8_t subject = 0; void setup() { // put your setup code here, to run once: derived1.setDefault( 3 ); derived2.setDefault( 5 ); } void loop() { // put your main code here, to run repeatedly: derived1.method( &subject, 1 ); // subject == 1 derived2.method( &subject, 2 ); // subject == 2 // won't comstack with this line: derived1.method( &subject ); // subject == 5 } 

L’erreur produite est:

 over-ride-load.ino: In function 'void loop()': over-ride-load.ino:39:29: error: no matching function for call to 'Derived1::method(uint8_t*)' over-ride-load.ino:39:29: note: candidate is: over-ride-load.ino:14:12: note: virtual void Derived1::method(uint8_t*, uint8_t) over-ride-load.ino:14:12: note: candidate expects 2 arguments, 1 provided Error compiling. 

Ce que je crois que vous recherchez, c’est la directive d’ using .

Vous avez tout fait correctement dans la Base . Bien que l’utilisation d’un paramètre par défaut soit (souvent) préférable à la définition d’une deuxième fonction, étant donné vos exigences (utiliser un membre), ce n’est pas possible ici: vous avez donc défini une deuxième fonction surchargée pour le réparer (et l’a défini inline – kudos!).

Mais le problème vient des classes dérivées. Si vous n’aviez pas remplacé la fonction virtuelle, tout se serait bien passé: les deux versions de method seraient disponibles. Mais vous devez la remplacer afin de “masquer” efficacement la version de base de la method(subject); avec method(subject,parameter); .

Ce que vous voulez faire est de “promouvoir” toutes les method de Base dans les différents Derived , pour leur donner une pondération égale. Comment? Avec la directive using .

Dans chaque définition Derived , mettez le code suivant:

 using Base::method; 

Cela “favorise” toute la méthode de Base dans la méthode Derived – tout en vous permettant de remplacer les méthodes individuelles. Je suggère que vous placiez cette ligne directement au-dessus de chaque substitution method() Derived .

D’après ce que j’ai lu ailleurs sur Stack Overflow, le remplacement doit avoir la même signature, c’est pourquoi il ne comstack pas.

Il va comstackr (si vous corrigez les erreurs de syntaxe). Il va comstackr parce que le remplacement a la même signature:

 virtual void method (uint8_t * subject, uint8_t parameter ) =0; 

contre

  void method( uint8_t * subject, uint8_t parameter ) 

D’autre part, l’option 2. (nom différent en faveur de la surcharge) semble toujours attrayante. Les surcharges peuvent parfois être délicates, déroutantes et intuitives.


Cependant, même si votre exemple est correct, vous constaterez peut-être que la procédure suivante ne fonctionne pas, ce qui peut être contre-intuitif:

 uint8_t b; Derived2 d2; d2.method(&b); 

Cela est dû au fonctionnement de la résolution de surcharge. L’option suggérée 2. résout sortingvialement ce problème. C’est pourquoi je vous recommande de le faire. Autres façons d’appeler la méthode dans parent:

  • Appelez d2.Base::method(&b);
  • Appelez la méthode à un seul argument uniquement via un pointeur / une référence d’object de base.
  • Ajouter en using Base::method; déclaration à chaque classe dérivée. Ceci est décrit plus en détail dans la réponse de John Burger.