web-dev-qa-db-ja.com

非constオブジェクトからconst関数を呼び出す

非constオブジェクトからconst関数を呼び出す必要があります。例を見る

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

呼び出し

getProcess().doSomeWork();

常にへの呼び出しになります

IProcess& getProcess()

別の呼び方はありますか

const IProcess& getProcess() const 

非定数メンバー関数から?私はこれまで使用しました

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

これはトリックを行いますが、過度に複雑に見えます。


編集:コードがリファクタリングされており、最終的には1つの関数のみが残ることに注意してください。

const IProcess& getProcess() const 

ただし、現在は副作用があり、const呼び出しはIProcessの別のインスタンスを返す場合があります。

話題を続けてください。

22
Chris

キャストを避けてください。これを_const Bar *_などに割り当て、それを使用してgetProcess()を呼び出します。

これを行うにはいくつかの衒学的な理由がありますが、コンパイラに潜在的に危険なことを強制することなく、何をしているのかをより明確にすることもできます。確かに、これらのケースにぶつかることは決してないかもしれませんが、この場合はキャストを使用しないものを書く方がよいでしょう。

10
MSN

const_castはキャスト用ですaway constness!

非constから安全なconstにキャストしているので、static_castを使用します。

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

技術的に言えば、const_castで一定にキャストできますが、演算子の実用的な使用法ではありません。 (古いcスタイルのキャストとは対照的に)新しいスタイルのキャストの目的は、キャストの意図を伝えることです。 const_castはコードの臭いであり、少なくともその使用法を確認する必要があります。一方、static_castは安全です。しかし、それはC++スタイルの問題です。

または、新しい(プライベート)constメソッドを作成し、それをdoOtherWorkから呼び出すことができます。

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

Consttemporaryを使用することもオプションです(「MSN」による回答)。

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

getProcess()getProcess() constが同じオブジェクトへの参照を返さない(ただし、修飾が異なる)場合は、_class Bar_の設計が不適切であることを示しています。関数のconstnessにオーバーロードすることは、動作が異なる関数を区別するための良い方法ではありません。

同じオブジェクトへの参照を返す場合は、次のようにします。

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

そして

_getProcess().doSomeWork();
_

まったく同じdoSomeWork()関数を呼び出すため、_const_cast_を使用する必要はありません。

4
CB Bailey

キャストが醜い場合は、代わりにBarにメソッドを追加して、_*this_へのconst参照を返すことができます。

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

次に、as_const().を前に付けるだけで、constanyBarメソッドを呼び出すことができます。例:

_as_const().getProcess().doSomeWork();
_
3
j_random_hacker

関数がオーバーロードされていない場合は、キャストのトリックを行う必要はありません。非constオブジェクトのconstメソッドを呼び出すことは問題ありません。禁止されているconstオブジェクトからnon-constメソッドを呼び出しています。メソッドがconst関数とnon-const関数でオーバーライドされている場合、オブジェクトをconstにキャストすると、次のトリックが実行されます。

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

編集:私は質問全体を読んでいませんでした。はい、thisポインターをconst_castするか、doOtherWork関数constを呼び出してconst IProcess&getProcess()constにする必要があります。

重要なのは、doSomeWorkを呼び出すのにconstオブジェクトは必要ないということです。それが目標なので、constメソッドを呼び出す必要がありますか?

別のオプションは、オーバーライドされた関数の名前を変更することです。 2つの関数が実際に異なる動作/副作用を持っている場合、これは本当に良い考えです。そうしないと、関数呼び出しの効果が明確になりません。

1
Judge Maygarden

テンプレートを定義する

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

と電話

addConst( getProcess() ).doSomeWork();
1

投稿者monjardin
別のオプションは、オーバーライドされた関数の名前を変更することです。これは、2つの関数の動作/副作用が実際に異なる場合は非常に良い考えです。そうでない場合、関数呼び出しの効果は明らかではありません。

IProcess&は、主にプロパティを介して他のコードでアクセスされます

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

そのため、名前を変更することはできませんでした。ほとんどの場合const呼び出し元の関数のネスはgetProcess()と一致するため、問題はありませんでした。

0
Chris

さて、あなたは宣言できますか

void doOtherWork const ()

それはそれをするでしょう。

0
user3458

Const_castメソッドが最善の選択肢だと思います。これは、C++のconstフレームワークの制限にすぎません。キャストを回避できる唯一の方法は、constIProcessインスタンスを返すメソッドを定義することだと思います。例えば。

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

Constオブジェクトから呼び出されたかどうかに応じて、DoOtherWorkに2つのgetprocess呼び出しのいずれかを呼び出させたいと思います。

私が提案できる最善の方法はこれです:

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

それがうまくいったとしても、これは私には悪臭のように見えます。オブジェクトの恒常性に応じてクラスの動作が根本的に変化することには非常に注意が必要です。

0
Roddy