2016-06-17 1 views
0

Je passe par cet article http://www.gotw.ca/publications/mill18.htm par Herb Sutter. L'auteur mentionne que l'écriture des interfaces non virtuelles sépare la spécification d'interface des « détails de mise en œuvre (à savoir l'interne du comportement personnalisable) »Pourquoi est-il préférable d'avoir des interfaces non virtuelles?

// Example 1: A traditional base class. 
// 
class Widget 
{ 
public: 
    // Each of these functions might optionally be 
    // pure virtual, and if so might or might not have 
    // an implementation in Widget; see Item 27 in [1]. 
    // 
    virtual int Process(Gadget&); 
    virtual bool IsDone(); 
    // ... 
}; 

Quel genre de détail de mise en œuvre (ou le comportement personnalisable) ne l'exemple ci-dessus spécifient? Je suis légèrement confus au sujet de ce qui ne va pas avec le code ci-dessus, qui nécessite des interfaces non-virtuelles

Répondre

0

Lorsque vous spécifiez l'interface publique virtuelle, int Process(Gadget&);, vous restreignez également l'interface d'extension pour qu'elle corresponde à cette interface publique. Celui qui étend cette classe devra le faire en implémentant la fonction Process.

Fournir une interface publique plus propre et un [lot] plus approprié de fonctions privées bien conçues pour la personnalisation permettra d'aborder nos deux objectifs individuellement.

1

Par customizable behavior cela signifie l'implémentation fournie par différents Derived Classes, c'est-à-dire les classes qui dériveront de votre Interface.

Considérez ceci:

class IMachine 
{ 
    public: 
     int ProcessJob() 
     { 
      cout << "Processing Job in By-Default way" << endl; 
     } 
     virtual int ProcessOrder() 
     { 
      cout << "Processing Order in By-Default way" << endl; 
     } 
}; 
class CMachine_A : public IMachine 
{ 
    public: 
     int ProcessJob() 
     { 
      cout << "Processing Job in Machine A's way" << endl; 
     } 
     int ProcessOrder() 
     { 
      cout << "Processing Order in Machine A's way" << endl; 
     } 
}; 
class CMachine_B : public IMachine 
{ 
    public: 
     int ProcessJob() 
     { 
      cout << "Processing Job in Machine B's way" << endl; 
     } 
     int ProcessOrder() 
     { 
      cout << "Processing Order in Machine B's way" << endl; 
     } 
}; 

IMachine *pMachine; 
CMachine_A oMachineA; 
CMachine_B oMachineB; 

pMachine = &oMachineA; 
pMachine->ProcessJob(); 
pMachine = &oMachineB; 
pMachine->ProcessJob(); 

Output: 
Processing Job in By-Default way 
Processing Job in By-Default way 

Ainsi, dans l'exemple ci-dessus, même si des points pMachine à différentes implémentations concrètes (lire: classes dérivées), la sortie est la même quelle que soit la mise en œuvre choisie/classe dérivée. C'est-à-dire que le customizable behavior de la machine A et de la machine B n'est pas entré en vigueur ou n'est pas honoré. Ainsi, en ayant non virtuelIMachine::ProcessJob(), l'interface IMachine a séparé/ignoré/supprimé la façon dont le travail sera traité quel que soit le type de machine (CMachine_A ou CMachine_B) qui est utilisé.

Maintenant, considérez ceci:

IMachine *pMachine; 
CMachine_A oMachineA; 
CMachine_B oMachineB; 

pMachine = &oMachineA; 
pMachine->ProcessOrder(); 
pMachine = &oMachineB; 
pMachine->ProcessOrder(); 

Output: 
Processing Order in Machine A's way 
Processing Order in Machine B's way 

Ici, quand pMachine des points à différentes implémentations concrètes (lire: classes dérivées), la sortie est fonction de la mise en œuvre choisie/classe dérivée. C'est-à-dire que le customizable behavior de la machine A et de la machine B est entré en vigueur ou honoré. Ainsi, en ayant virtuelIMachine::ProcessOrder(), l'interface IMachine a gardé l'option/voie ouverte dans laquelle la commande sera traitée en fonction du type de machine (CMachine_A ou CMachine_B) qui est utilisé.

En bref, l'interface IMachine a gardé le ProcessOrder comme virtual mise en œuvre donc différente/classe dérivée peut fournir customizable behavior pour la fonction ProcessOrder.