2010-08-26 9 views
2

Dire que j'ai une classe abstraiteUne méthode qui ne peut être appelée que lorsqu'on se réfère à une classe de base? C++

class NecessaryDanger 
{ 
public: 
    virtual void doSomethingDangerous() =0; 
} 

et une classe qui est dérivée de cette classe:

class DoesOtherStuff : public NecessaryDanger 
{ 
    //stuff 
    void otherMethod(); 
    void doSomethingDangerous(); 
} 

est-il un moyen que je ne peux pas permettre l'accès des doSomethingDangerous() comme

DoesOtherStuff d; 
d = DoesOtherStuff(); 
d.otherMethod(); //OK 
d.doSomethingDangerous(); //error 

NecessaryDanger* n = &d; 
n->doSomethingDangerous(); //OK 

Je ne suis pas encore très bon en C++, donc le code ci-dessus n'est peut-être pas tout à fait correct, mais vous avez peut-être l'idée. J'ai un ensemble de classes qui doivent avoir la capacité de faire "quelque chose de dangereux" (à leur manière particulière) qui pourrait causer des problèmes si plus d'un objet de ces classes fait cette chose dangereuse. Je voudrais avoir une classe de gestionnaire qui a un pointeur NecessaryDanger à un seul objet. Si la méthode doSomethingDangerous ne pouvait être appelée que par un objet NecessaryDanger, il serait plus difficile pour un appel accidentel de faire quelque chose de Dangerous et de me causer des maux de tête sur la route.

Merci d'avance pour l'aide. Désolé d'avance si c'est une question stupide!

Répondre

4

Bien sûr. Il suffit de le faire private dans la classe dérivée et public dans la base.

Bien sûr, si NecessaryDanger est une base publique, n'importe qui peut lancer et appeler. Vous pouvez en faire une base privée et utiliser friend.

class DoesOtherStuff : private NecessaryDanger 
{ 
    //stuff 
    void otherMethod(); 

private: 
    void doSomethingDangerous(); 

    friend class DangerManager; 
} 
+0

Pourriez-vous m'expliquer comment je pourrais le faire avec un ami? Devrais-je faire dériver de la base comme classe dérivée: base privée, rendre la méthode dangereuse privée et déclarer la classe de base comme amie? Pourquoi une base privée empêche-t-elle le casting? Merci – Johnny

+0

Mise à jour avec l'exemple de code.C'est à peu près ce que vous décrivez, mais faites de la classe manager l'ami: vous voulez qu'il ait un accès complet aux choses «privées». Rendre la base privée empêche de lancer à la base parce que, quand quelque chose est privé, rien en dehors de la classe elle-même et de ses amis ne peut dire qu'elle existe. – Potatoswatter

+0

Merci pour le montage! Mais cela ne me permettra-t-il pas d'appeler cette méthode n'importe où dans DangerManager pour n'importe quel objet? Et si je dois appeler doSomethingDangerous quelque part en dehors de DangerManager dans un autre contexte? Je l'appellerais toujours de l'intérieur du gestionnaire de danger comme DoesOtherStuff d = DoesOtherStuff(); d.doSomethingDangerous; droite? Y at-il un moyen que je serais seulement en mesure d'appeler cela comme NecessaryDanger * n; n-> doSomethingDangerous()? Merci de vous occuper de moi. – Johnny

2

Retirez le classificateur virtual dans la superclasse afin que le compilateur ne compile-temps de liaison basée sur le type de variable au lieu d'exécution liaison en fonction du type d'objet.

+0

Comment l'élimination de "virtual" résout-elle le problème? Ce serait plus susceptible de tout casser. – Potatoswatter

+0

L'appel 'doSomethingDangerous()' sur une variable 'NecessaryDanger' appellera' NecessaryDanger :: doSomethingDangerous', quel que soit le type de l'objet contenu dans la variable. Enlever 'virtual' rompt le polymorphisme pour cette méthode, ce que veut le demandeur. –

+0

Comment at-il indiqué qu'il ne veut pas de polymorphisme? – Potatoswatter

0

Miser sur la réponse Potatswatter :)

Here est le conseil de Herb: (en particulier 1 et 2) applicables dans ce contexte.

Ligne directrice # 1: Je préfère faire interfaces nonvirtual, en utilisant la méthode modèle .
Ligne directrice 2: Préférez rendre privées les fonctions virtuelles .
Principe 3: uniquement si les classes dérivées doivent invoquer l'implémentation de base d'une fonction virtuelle , sécurisez la fonction virtuelle .

Pour le cas particulier de la destructor seulement:

Directive n ° 4: Une classe de base destructor devrait être publics et virtuels, ou protégé et nonvirtual.