Home > .NET Framework Archive

.NET Framework Archive

仮想関数を generic にする

C++では、メンバ関数テンプレートを仮想関数にできない。ところが、C++/CLI ではテンプレートに良く似た機能である generic を仮想関数につけることができる。これにはどんなトリックが隠されているのだろう?

まずは、次のようなコードから。


public ref class Base // ref class なので参照型
{
public:
  generic <typename T> // generic を仮想関数につける
  virtual int Func(T in) { // T は任意の型
      return sizeof(in); // T 型のサイズを返す(本当は size_t だけど)
  }
};

public ref class Derived: public Base
{
public:
  generic <typename T>
  virtual int Func(T in) override { // Base::Func を override
      return sizeof(in) * 2; // T 型のサイズを倍にして返す
  }
};

これはTがどんな型であっても正しく動作する。Derived のインスタンスを Base のハンドルで参照しても、Derived 側の Func が呼ばれる。完璧だ。

C++ では、Tの型が決まらないと仮想関数テーブルを構築できず、Tの型を知るためには全ての翻訳単位を調べなければならない。よって、このようなメンバ関数は禁止されている。そして、以前のエントリでは「なんだ、その都度 JIT コンパイルすればいいじゃん」という結論で終わっていた。今回は、これをもう少し調べてみようと思う。

続きを読む

コレクションの永続化

.NET Framework で独自のコントロールを作りたい場合は、UserControl から派生させたクラスを用意すればよい。一般的に、自作コントロールには独自のプロパティも含まれており、そのプロパティが自作クラスになっていることも多いはず。今回は、自作クラスの配列をプロパティとして持たせたところ大ハマリしたという話。

ある自作コントロールに自作クラス MyItem の配列をプロパティとして持たせたいと思い、System::Collections::Generic::List<MyItem^>^ 型のプロパティ MyItemList を追加することにした。cli::array ではなく List を使っているのは vector っぽく使いたいためだが、この違いは本質ではない(と思う)。悲劇の始まりは次のようなコードからだ。


ref class MyItem;
ref class MyCtrl : public System::Windows::Forms::UserControl
{
// ... 色々あって、

private:
  System::Collections::Generic::List<MyItem^>^ m_itemList; // リストの実体

public:
  MyCtrl(void) {
      InitializeComponent();

      // コンストラクタで m_itemList を確保する
      m_itemList = gcnew System::Collections::Generic::List<MyItem^>;
  }

public:
  property System::Collections::Generic::List<MyItem^>^ MyItemList { // このプロパティは
      System::Collections::Generic::List<MyItem^>^ get() { // get だけしか持っていない(set は許可しない)
          return m_itemList; // 中身は自由にしても構わないが、リストそのものはコチラで管理させてくれ
      }
  }

// ... 色々あるよね
};

続きを読む

Index of all entries

Home > .NET Framework Archive

Search
Feeds

Return to page top