thisキーワードの危険性 Edit

メンバ初期化子にthisキーワードを使うのはよくない Edit

MessageButtonクラスに注目。
先にbutton_を初期化してからmessage_を初期化しています。
そのため、もしButtonクラスのコンストラクタの中でIButtonListener::onButtonPushed()が
呼ばれるような実装の変更があった場合、未初期化のmessage_を出力することになってしまいます。

まず

message_のコンストラクタを先にすればいい

という意見も出てくるかと思います。

今回はそれでいいのですが、

thisなものをメンバ変数に渡すときは、その時点でリスナに対する呼び出しの準備が完了している必要がある

ということを言いたかったのです。

message_を先にコンストラクトしたとしても、
MessageButtonクラスのコンストラクタは完了していない状態です。
その状態で他のオブジェクトからメソッドを呼ばれるのはものすごく嫌な感じです。

今回のようなシンプルな例だとそんなに問題ないのですが
オブジェクト間でリスナクラスを受け渡ししているような場合だと
複雑になってきてそこまで考慮できなくなってくるんですよね。

VC8.0では警告に扱っている

コード1
すべてを展開すべてを収束
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 
 
 
 
 
-
|
|
|
|
|
!
 
 
 
-
|
|
|
-
!
|
|
|
-
|
!
|
|
|
!
 
 
 
-
|
|
|
|
-
!
|
|
|
-
|
!
|
|
|
-
|
!
|
|
|
|
!
 
 
-
|
|
|
!
 
 
 
#include <iostream>
//
 
/// ボタンのイベントを受け取るクラス。
class IButtonListener
{
public:
    virtual ~IButtonListener(){}
    
    /// ボタンが押されたときに呼ばれる。
    virtual void onButtonPushed()=0;
};
 
/// ボタンクラス。
class Button
{
public:
    Button( IButtonListener& aListener )
    : listener_( aListener )
    {
    }
 
    /// 押しボタンイベントを発行する。
    void push()
    {
        listener_.onButtonPushed();
    };
    
private:
    IButtonListener& listener_;
};
 
/// ボタンが押されたらメッセージを出力するクラス。
class MessageButton : public IButtonListener
{
public:
    MessageButton( const char* aMessage )
    : button_( *this )
    , message_( aMessage )
    {
    }
    
    // IButtonListener
    virtual void onButtonPushed()
    {
        std::cout << message_ << "\n";
    }
    
    /// ボタンを押す。
    void push()
    {
        button_.push();
    }
    
private:
    Button button_;
    const std::string message_;
};
 
/// メイン関数。
int main (int argc, char * const argv[]) {
    MessageButton button( "Button Pushed Message" );
    button.push();
    return 0;
}
 
// EOF
コード2
すべてを展開すべてを収束
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 
-
|
|
|
!
 
 
 
-
|
|
|
|
-
!
|
|
|
-
|
|
!
|
|
|
!
 
 
/// メッセージを返すインターフェースクラス。
class IMessage
{
public:
    virtual ~IMessage(){}
    virtual std::string createMessage()const=0;
};
 
/// HelloWorldを出力し、その後任意のメッセージを出力するMessageButton。
class HelloWorldButton : public MessageButton
{
public:
    HelloWorldButton( const IMessage& aIMesssage )
    : MessageButton( "Hello World" )
    , message_( aIMesssage )
    {
    }
    
    // MessageButton
    virtual void onButtonPushed()
    {
        MessageButton::onButtonPushed();
        std::cout << message_.createMessage();
    }
    
private:
    const IMessage& message_;
};
 

リスナーとしてthisキーワードを渡す場合 Edit

実装としてthisキーワードを渡す場合 Edit


    ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS