none
イベント定義(C++/CLI) RRS feed

  • 質問

  • お世話になっております。

    VS2008を使用しております。

    delegate void MethodPrint(void);
    void Print(){System::Console::WriteLine("Call Print")};

    ref class Test
    {
     public:
        event MethodPrint^ OnClick;
    };

    main()
    {
       Test^ obj += gcnew MethodPrint(Print);
        obj->OnClick();// コンパイルエラー

    エラー 1 error C3767: 'Test::OnClick::raise': 候補の関数はアクセス可能ではありません。 

    確かにildasmでみてえみると、hidebysig がつけられ隠蔽されていました。

    これはなぜなのでしょうか?

     

    2010年11月24日 7:11

回答

  • 残念ながらこういった情報源(設計思想的な情報など)は英語である場合がほとんどです。今回は意訳しますが、一文ずつ、少しづつ翻訳していくなど慣れてくださいね。また、理解の前提としてC#やILといった知識が必要です。

    概要のみ意訳です。

    私の理解している範囲でですが、C++/CLIを除くほとんどのマネージ言語は、アプリケーションのILに.fireメソッドを用意しません。その結果、.fireメソッドは暗黙のうちにprivateになります。そのため、そのイベントを実行(呼び出し)できるのは、イベントを用意したクラスだけです。そのクラスの子クラスはprivateのため実行(呼び出し)できません。従って、イベントを実行(呼び出し)できるようにする為に、protectedのOnEventメソッドをイベントごとに用意する必要があります。そうすれば、子クラスからもイベントを実行(呼び出し)できるようになります。

    C++/CLIでは.fireメソッドを用意します。raiseメソッドをoverrideしなかった場合、イベントがpublicもしくはprotectedだったら、raiseメソッドはprotectedになります。イベントがprivateなら、raiseメソッドはprivateになります。従って多くの状況において、OnEventを用意しなくてもよくなります。

    • 編集済み kozz 2010年12月7日 15:14 raise > .fire
    • 回答としてマーク OTAKA 2010年12月9日 5:14
    2010年12月7日 15:00

すべての返信

  • // まともにコンパイルできないような。

    通常のイベントは、それを宣言するクラス内部でのみそのデリゲートを実行できます。main は Test クラスの外部ですから、OnClick イベントに対しては += および -= のみの操作しかできません。

    Test クラスに Click メソッドを用意しそこで OnClick を呼び出すといったことになります。

    // イベントが Click で、そのイベントを起こすメソッドが OnClick、というのが一般的な命名です。

    2010年11月24日 7:29
  • >これはなぜなのでしょうか?

    仕様です。但し、OverrideすればAccessできます。

    以下のパターンを利用します。

    delegate void MethodPrint(void);
    
    void Print(){System::Console::WriteLine("Call Print");}
    void Print2(){System::Console::WriteLine("Call Print 2");}
    
    ref class Test
    {
     public:
      event MethodPrint^ Click
    	{
    		void add(MethodPrint ^methodPrint) 
    		{
    			delMethodPrint = (MethodPrint^)Delegate::Combine(delMethodPrint,methodPrint); 
    		}
    
    		void remove(MethodPrint ^methodPrint) 
    		{
    			delMethodPrint = (MethodPrint^)Delegate::Remove(delMethodPrint,methodPrint);
    		}
    
    		void raise() 
    		{
    			delMethodPrint->Invoke();
    		}
    	}
    
    protected:
    	MethodPrint ^delMethodPrint;
    };
    
    ref class Test2
    {
     public:
      event MethodPrint^ Click;
    	
    	void OnClick()
    	{
    		Click();
    	}
    };
    
    
    int main(array<System::String ^> ^args)
    {
    	Test ^obj = gcnew Test();
    
    	obj->Click += gcnew MethodPrint(&Print);
    	obj->Click();
    
    	Test2 ^obj2 = gcnew Test2();
    
    	obj2->Click += gcnew MethodPrint(&Print2);
    	obj2->OnClick();
    
    	return 0;
    }
    
    

     

    細かいError Checkは省いています。Test2の使い方がよく使われます。

     

     

    2010年11月25日 11:10
  • ご返事ありがとうございます。

    dotNET的考え方ととらえるべきでしょうか。

    いつもは、Test2クラスと同じ実装で特に意識してなかったのですが、
    Testクラスと同じようにeventの展開をオーバーライドする形で実装したときに、
    あれ、直接呼べるけどいいのかなと疑問をもち、下記のよう隠蔽すべきなのかなと思ったのですが、
    なぜ、コンパイラはhidebysig をわざわざつけているのかなと疑問に思い質問させていただきました。
    dotNETの仕様を踏襲する場合は、下記のようにするべきでしょうか。

    event MethodPrint^ Click
    {
    private:
      void raise()
      {
      }
    }

    2010年11月26日 1:42
  • .NET的というより、C#的、IL的という表現のが近いでしょう。Managed Languageの中心はC#であるイメージがあります。

     

    >なぜ、コンパイラはhidebysig をわざわざつけているのかな

    以下が参考になります。 

    [C++/CLI event issues]

      http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/ff743ebd-dba9-48bc-a62a-1e65aab6f2f9/

     

    >下記のようにするべきでしょうか。

    制御子はAssemblyやClassの要件に応じて使い分けですね。public以外の制御子にして、OnXXX経由で統一したほうがよいと個人的に思います。

     

    [Member Visibility]

      http://msdn.microsoft.com/en-us/library/45x418az(v=VS.90).aspx

    2010年11月26日 11:00
  • ご返事ありがとうございます。

    [C++/CLI event issues]

    がんばって訳してみましたが、英文読めないもので理解できませんでした。

    概要でも教えていただけるとありがたいのですが・・・

    2010年12月6日 8:03
  • 残念ながらこういった情報源(設計思想的な情報など)は英語である場合がほとんどです。今回は意訳しますが、一文ずつ、少しづつ翻訳していくなど慣れてくださいね。また、理解の前提としてC#やILといった知識が必要です。

    概要のみ意訳です。

    私の理解している範囲でですが、C++/CLIを除くほとんどのマネージ言語は、アプリケーションのILに.fireメソッドを用意しません。その結果、.fireメソッドは暗黙のうちにprivateになります。そのため、そのイベントを実行(呼び出し)できるのは、イベントを用意したクラスだけです。そのクラスの子クラスはprivateのため実行(呼び出し)できません。従って、イベントを実行(呼び出し)できるようにする為に、protectedのOnEventメソッドをイベントごとに用意する必要があります。そうすれば、子クラスからもイベントを実行(呼び出し)できるようになります。

    C++/CLIでは.fireメソッドを用意します。raiseメソッドをoverrideしなかった場合、イベントがpublicもしくはprotectedだったら、raiseメソッドはprotectedになります。イベントがprivateなら、raiseメソッドはprivateになります。従って多くの状況において、OnEventを用意しなくてもよくなります。

    • 編集済み kozz 2010年12月7日 15:14 raise > .fire
    • 回答としてマーク OTAKA 2010年12月9日 5:14
    2010年12月7日 15:00
  • ご返事ありがとうございます。

    すみません、頑張ってみます。

     

    2010年12月9日 5:14