Frage

Ich brauche eine konstante Funktion von einem nicht-konstanten Objekt aufrufen. Siehe Beispiel

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();        
  }
};

Der Aufruf

getProcess().doSomeWork();

wird immer führt zu einem Aufruf von

IProcess& getProcess()

Gibt es eine andere Art und Weise zu nennen

const IProcess& getProcess() const 

von einer nicht konstanten Elementfunktion? Ich habe bisher verwendeten

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

, die den Trick funktioniert aber scheint zu kompliziert.


Edit:. Ich sollte dieser Code erwähnen Refactoring wird und schließlich nur eine Funktion bleiben

const IProcess& getProcess() const 

Doch derzeit gibt es eine Nebenwirkung und der const Anruf eine andere Instanz von iProcess einen Teil der Zeit zurückkehren.

Bitte halten Sie beim Thema.

War es hilfreich?

Lösung

Vermeiden Sie die genannte Besetzung. Zuweisen, dies zu einem const Bar * oder was auch immer und verwendet, die getProcess() anrufen

Es gibt einige Gründe, pedantisch, das zu tun, aber es macht es auch klar, was Sie tun, ohne die Compiler zu zwingen, etwas potenziell unsicher zu machen. Zugegeben, können Sie nie die Fälle getroffen, aber man könnte genauso gut etwas schreiben, das nicht eine Besetzung in diesem Fall nicht verwendet.

Andere Tipps

const_cast ist für das Gießen von entfernt Konstantheit!

Sie sind Gießen von Nicht-const const, die sicher ist, so verwenden static_cast:

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

Ich techincally bedeuten Sprechen Sie in Konstantheit mit const_cast werfen können, aber es ist nicht eine pragmatische Nutzung des Betreibers. Der Zweck des neuen Casts (im Vergleich zu den alten c-Casts), ist die Absicht des Gusses zu kommunizieren. const_cast ist ein Code Geruch, und es ist die Verwendung sollte zumindest überprüft werden. static_cast auf der anderen Seite ist sicher. Aber es ist eine Frage des C ++ Stils.

Sie können auch eine neue (privat) const Methode erstellen, und rufen Sie das aus doOtherWork:

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

Mit einem const temporären wird auch eine Option (Antwort von "MSN"):

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

Wenn getProcess() und getProcess() const nicht einen Verweis auf das gleiche Objekt zurückkehren (aber anders qualifiziert), dann wäre es ein schlechtes Design von class Bar zeigen. Eine Überlastung auf der constness der Funktion kein guter Weg ist Funktionen mit unterschiedlichen Verhaltensweisen zu unterscheiden.

Wenn sie einen Verweis auf das gleiche Objekt zurückkehren, dann:

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

und

getProcess().doSomeWork();

Anruf genau die gleiche doSomeWork() Funktion, so gibt es keine Notwendigkeit, die const_cast zu verwenden.

Wenn die Besetzung für Sie zu hässlich ist, könnten Sie stattdessen eine Methode in dem Bar, dass einfach eine konstante Referenz wieder in *this:

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

Sie können dann rufen Sie jeder const Methode in Bar nur durch das Voranstellen as_const()., z.

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

Sie müssen jedes Casting Betrügerei nicht tun, wenn die Funktion nicht überlastet wird. eine konstante Methode eines nicht-konstantes Objekt aufrufen ist in Ordnung. Es ist eine nicht-const-Methode aus einem konstanten Objekt aufrufen, die verboten ist. Wenn die Methoden mit einem const und nicht-konstanter Funktion außer Kraft gesetzt werden, dann das Objekt const Gießen den Trick:

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

EDIT: Ich habe nicht die ganze Frage gelesen. Ja, Sie müssen const_cast die diese Zeiger oder machen die doOtherWork Funktion const rufen const iProcess & getProcess () const .

Der Punkt bleibt, dass Sie rufen Sie nicht ein konstantes Objekt müssen doSomeWork . Da, dass das Ziel ist, tun Sie das konstante Methode müssen genannt?

Eine andere Möglichkeit wäre es, die übergangen Funktionen umbenennen. Dies wäre eine wirklich gute Idee, wenn die beiden Funktion tatsächlich unterschiedliche Verhalten / Nebenwirkungen haben. Andernfalls würde die Wirkung des Funktionsaufrufes nicht offensichtlich sein.

eine Vorlage definieren

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

und Anruf

addConst( getProcess() ).doSomeWork();

Nun, können Sie erklären

void doOtherWork const ()

Das würde es tun.

Ich denke, die const_cast Methode ist die beste Option. Dies ist nur eine Begrenzung des konst Rahmen in C ++. Ich denke, der einzige Weg, das Gießen vermeiden könnte, ist eine Methode zu definieren, die unabhängig const iProcess Instanz zurückgibt. Zum Beispiel.

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

Ich nehme an, Sie DoOtherWork man anrufen mögen Ihre zwei getprocess Anrufe je nach dem, ob es von einem konstanten Objekt aufgerufen wird oder nicht.

Das Beste, was ich vorschlagen kann, ist dies:

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     
  }
};

Auch wenn das funktioniert, sieht es wie ein schlechter Geruch zu mir. Ich wäre sehr vorsichtig mit der das Verhalten Klasse radikal nach dem Konstantheit eines Objekts zu ändern.

  

Veröffentlicht von Monjardin
   Eine andere Möglichkeit wäre es, die übergangen Funktionen umbenennen. Dies wäre eine wirklich gute Idee, wenn die beiden Funktion tatsächlich unterschiedliche Verhalten / Nebenwirkungen haben. Andernfalls würde die Wirkung des Funktionsaufrufes nicht offensichtlich sein.

iProcess & ist in anderem Code meist durch eine Eigenschaft zugegriffen

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

so wurde die Umbenennung keine Option. Mehrheit der Zeit const ness der rufenden Funktion entspricht getProcess (), so gibt es kein Problem.

Sie sind im Grunde mit Umbenennung der anderen Methode oder const_cast stecken.

BTW, ist dies einer der Gründe, die Copy-on-Write-Smart-Pointer tatsächlich in C nicht gut funktionieren ++. Eine Kopie-on-write Smart Pointer ist eine, die unendlich geteilt werden kann. Wenn ein Benutzer die Daten in einem nicht konstanten Kontext zugreift, wird eine Kopie der Daten gemacht (wenn der Benutzer die eindeutige Referenz nicht halten). Diese Art des Zeigers kann sehr bequem zu bedienen sein, wenn große Datenstrukturen teilen, die nur einig Kunden ändern müssen. Die „logische“ Implementierung ist ein const haben und eine nicht-const operator->. Die const Version gibt nur die zugrunde liegende Referenz. Die nicht-const-Version funktioniert die einzigartige Referenzprüfung und Kopieren. Es ist immer sinnvoll sein, weil ein nicht-const Smart-Pointer wird die nicht-const operator-> standardmäßig verwenden, auch wenn Sie die const-Version verwenden wollten. Die const_cast Anforderung macht es sehr benutzerunfreundlich.

Ich bin begrüßen alle, die mich falsch und zeigt eine benutzerfreundliche Copy-on-Write-Zeiger in C ++ beweist ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top