初めてのC++/CLIその3

今回は型についてです。C#やっててC++を知らない場合、class/structで混乱するかもしれません。C++におけるclass/structは単にアクセス修飾子のデフォルトがprivate/publicの違いだけです。では値型、参照型は何で決まるのかというとref/valueキーワードに因ります。

#include "stdafx.h"

using namespace System;

// デリゲート
delegate void Func();

// 親クラス(抽象クラス)
ref class BaseClass abstract {
  int num;
public:
  BaseClass() : num(0) {}
  // イベント
  event Func^ FuncHandler;

  void Say() {
    // イベントが設定されていたら呼び出す
    if (FuncHandler != nullptr) 
      FuncHandler();
  }

  // 仮想関数
  virtual void Method1() {Console::WriteLine("BaseClass::Method1");}
  virtual void Method2() {Console::WriteLine("BaseClass::Method2");}

  // プロパティ
  property int Number {
    int get() {
      return num;
    }
    void set(int value) {
      num = value;
    }
  }
};

// 派生クラス(継承禁止)
ref class SubClass sealed : public BaseClass {
public:
  // オーバーライド
  virtual void Method1() {Console::WriteLine("SubClass::Method1");}
  // 親クラスのMethod2を上書きしない(newキーワード)
  virtual void Method2() new {Console::WriteLine("SubClass::Method2");}
};


// インタフェース
interface class IInterface {
  void Method();
};

// 参照型のクラス
ref class RefClass : IInterface {
public:
  // インタフェースの実装はpublicで無ければならない
  void Method() {}
};

// 参照型の構造体(クラスとはデフォルトのアクセス修飾子が違うだけ
ref struct RefStruct : IInterface {
  // structのデフォルトはpublic
  // C#のclass/structとは違うので注意
  void Method() {}
};

// 値型のクラス
value class ValueClass {
public:
  void Method() {}
};

// 値型の構造体
value struct ValueStruct {
  void Method() {}
};

// 列挙型クラス
enum class EnumClass {
  // publicつけなくても公開。class/structの差が無い?
  One,Two,Three
};

// 列挙型構造体(フラグ属性あり)
[Flags]
enum struct EnumStruct {
  One,Two,Three
};

void SayHello() 
{
  printf("Hello!\n");
}

void SayGoodby()
{
  printf("Goodby!\n");
}


int _tmain()
{
  // 派生クラスを生成して、ベースクラスに代入
  BaseClass^ bc = gcnew SubClass;

  // 仮想関数呼び出し
  // 派生クラスのMethod1が呼ばれる
  bc->Method1();
  // 親クラスのMethod2が呼ばれる(newがあるので親クラスのMethod2は隠されない)
  bc->Method2();

  // ベースクラスのイベントに登録
  bc->FuncHandler += gcnew Func(SayHello);
  bc->FuncHandler += gcnew Func(SayGoodby);
  // イベント呼び出し
  bc->Say();

  // プロパティ
  bc->Number = 10;
  Console::WriteLine("Number = {0}", bc->Number);
  
  // 列挙型
  Console::WriteLine(EnumClass::One);
  // 列挙型(フラグ属性があるのでORに対応)
  Console::WriteLine(EnumStruct::Two | EnumStruct::Three);
  
  Console::ReadLine();
}

/* 結果
SubClass::Method1
BaseClass::Method2
Hello!
Goodby!
Number = 10
One
Two, Three*/

マネージドコードだけだとC#とあんま変わらない感じですが、これにネイティブコードが混じってくると分かり難くなるんだろうなぁ・・・