Question

Je dois appeler une fonction const à partir d'un objet non-const. Voir exemple

struct IProcess {
   virtual bool doSomeWork() const = 0L;
};
class Foo : public IProcess {    
  virtual bool doSomeWork() const {
    ...
  }
};

class Bar
{
public:
   const IProcess& getProcess() const {return ...;}
   IProcess& getProcess() {return ...;}

   void doOtherWork {
    getProcess().doSomeWork();        
  }
};

Appeler

getProcess().doSomeWork();

entraînera toujours un appel à

IProcess& getProcess()

Y a-t-il un autre moyen d'appeler

const IProcess& getProcess() const 

à partir d'une fonction membre non constante? J'ai jusqu'à présent utilisé

const_cast<const Bar*>(this)->getProcess().doSomeWork();

qui fait l'affaire mais semble trop compliqué.

Éditer: je devrais mentionner que le code est en cours de refactoring et qu’il ne restera finalement qu’une fonction.

<*>

Cependant, il existe actuellement un effet secondaire et l’appel de const peut parfois renvoyer une instance différente de IProcess.

Veuillez rester sur le sujet.

Était-ce utile?

La solution

Évitez la conversion: attribuez-le à un const Bar * ou à un autre moyen et utilisez-le pour appeler getProcess () .

Il existe certaines raisons pédantes de faire cela, mais cela rend également plus évident ce que vous faites sans obliger le compilateur à faire quelque chose de potentiellement dangereux. Certes, vous pouvez ne jamais toucher à ces cas, mais vous pouvez aussi bien écrire quelque chose qui n’utilise pas de casting dans ce cas.

Autres conseils

const_cast permet de chasser la constness!

La conversion de non-const à const est sûre, utilisez donc static_cast :

   static_cast<const Bar*>(this)->getProcess().doSomeWork();

Je veux dire techniquement, vous pouvez transtyper constness avec const_cast , mais ce n'est pas une utilisation pragmatique de l'opérateur. Le but des nouveaux styles (par rapport à l'ancien type C) est de communiquer l'intention du casting. const_cast est une odeur de code, et son utilisation devrait être revue au minimum. static_cast est en revanche sûr. Mais c’est une question de style C ++.

Vous pouvez également créer une nouvelle méthode const (privée) et l'appeler depuis doOtherWork :

  void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }

Utiliser un const temporaire est également une option (réponse par "MSN"):

   const Bar* _this = this;
   _this->getProcess().doSomeWork();

Si getProcess () et getProcess () const ne renvoient pas de référence au même objet (mais qualifié différemment), cela indiquerait une mauvaise conception de class bar . Surcharger la const de la fonction n’est pas un bon moyen de distinguer les fonctions ayant des comportements différents.

S'ils renvoient une référence au même objet, alors:

const_cast<const Bar*>(this)->getProcess().doSomeWork();

et

getProcess().doSomeWork();

appelle exactement la même fonction doSomeWork () , de sorte qu'il n'est pas nécessaire d'utiliser la const_cast .

Si la conversion est trop laide pour vous, vous pouvez également ajouter une méthode à Bar qui renvoie simplement une référence const à * this :

Bar const& as_const() const {
    return *this;    // Compiler adds "const" without needing static_cast<>
}

Vous pouvez ensuite appeler une méthode quelconque const dans Bar en ajoutant simplement as_const (). , par exemple:

as_const().getProcess().doSomeWork();

Vous n'êtes pas obligé de faire une supercherie de casting si la fonction n'est pas surchargée. L'appel d'une méthode const d'un objet non-const est acceptable. Il appelle une méthode non-const depuis un objet const qui est interdit. Si les méthodes sont remplacées par une fonction const et non-const, alors le transtypage de l'objet en const fera l'affaire:

const_cast<const IProcess&> (getProcess()).doSomeWork();

EDIT: Je n’ai pas lu toute la question. Oui, vous devez const_cast le pointeur this ou obliger la fonction doOtherWork à appeler const IProcess & amp; getProcess () const .

Il reste que vous n'avez pas besoin d'un objet const pour appeler doSomeWork . Puisque c'est l'objectif, avez-vous besoin de la méthode const appelée?

Une autre option serait de renommer les fonctions écrasées. Ce serait une très bonne idée si les deux fonctions ont en réalité un comportement / des effets secondaires différents. Sinon, l'effet de l'appel de fonction ne serait pas évident.

définir un modèle

template< class T >
const T & addConst ( T & t ) 
{
    return t;
}

et appelez

addConst( getProcess() ).doSomeWork();

Eh bien, pouvez-vous déclarer

void doOtherWork const ()

?

Cela le ferait.

Je pense que la méthode const_cast est votre meilleure option. Ceci est juste une limitation du framework const en C ++. Je pense que la seule façon d’éviter le casting est de définir une méthode qui retourne une instance const IProcess malgré tout. Par exemple.

const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();

Je suppose que vous souhaitez que DoOtherWork appelle l'un de vos deux appels getprocess selon qu'il est appelé depuis un objet const ou non.

Le mieux que je puisse suggérer est le suivant:

class Bar
{
public:
   const IProcess& getProcess() const {return ...;}
   IProcess& getProcess() {return ...;}

   void doOtherWork {            // should use getProcess()      
    getProcess().doSomeWork();        
  }
   void doOtherWork const {
    getProcess().doSomeWork();   // should use getProcess() const     
  }
};

Même si cela fonctionne, cela ressemble à une mauvaise odeur pour moi. Je serais très prudent que le comportement de la classe change radicalement en fonction de la constance d'un objet.

  

Publié par monjardin
   Une autre option serait de renommer les fonctions remplacées. Ce serait une très bonne idée si les deux fonctions ont en réalité un comportement / des effets secondaires différents. Sinon, l'effet de l'appel de fonction ne serait pas évident.

IProcess & amp; est utilisé dans un autre code principalement via une propriété

__declspec(property(get=getProcess)) IProcess& Process;

donc renommer n'était pas une option. La majorité du temps const de la fonction appelante correspond à getProcess (), il n'y a donc pas eu de problème.

Vous êtes essentiellement obligé de renommer l’autre méthode ou const_cast.

BTW, c’est l’une des raisons pour lesquelles les pointeurs intelligents de copie sur écriture ne fonctionnent pas bien en C ++. Un pointeur intelligent de copie sur écriture est un pointeur pouvant être partagé à l'infini. Lorsqu'un utilisateur accède aux données dans un contexte non-const, une copie des données est faite (si l'utilisateur ne détient pas la référence unique). Ce type de pointeur peut être très pratique lorsque vous partagez des structures de données volumineuses que seuls certains clients doivent modifier. Le plus "logique" l'implémentation consiste à avoir un opérateur constant et un opérateur non constant - > ;. La version const ne renvoie que la référence sous-jacente. La version non-const effectue la vérification et la copie des références uniques. Cela ne peut pas être utile car un pointeur intelligent non const utilisera l'opérateur non const- > par défaut, même si vous vouliez utiliser la version const. L'exigence de const_cast le rend très hostile à l'utilisateur.

J'accueille toute personne qui me prouve le contraire et affiche un pointeur convivial pour la copie sur écriture en C ++ ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top