ホーム > 読んだ > 国内

C++/CLI 研究

書誌

tagC++
text唯野
author渡邊誠人
publisherソフトバンク
year『C MAGAZINE 2005.4』p.46-54

目次

1感想
2抄録

履歴

2005.12.24読了
2005.12.28公開
2007.2.9修正

感想

C++/CLI は VC2003 でのマネージ拡張を更に推し進めたものである。そのため .net Framework プログラミングにおける C++ 言語拡張といってしまえばそれまでとなるが、C++/CLI では C# と並び標準化をも意識している──正しくはマネージ拡張の標準化作業版が C++/CLI なのだということである。C++ の拡張性を維持したまま Java などの便利な点を取り込んだといってしまっては乱暴か。しかし、GC、interface、Generic (= template)、finally キーワードなどは Java と同様である。これ以外では列挙型クラス/構造体、イベントハンドラ/オーバーライド専用を含む新しいキーワード(予約語)などが含まれている。

かくいう私もマネージ拡張や C# は MS だけのプロプライエタリな技術としか思っていなかった。しかし、C++/CLI は現状の肥大化した C++ に対する目指すべきひとつの方向性だと思う。コンピュータの歴史においては、基本的に複雑化しすぎたもの(学習曲線のきつくなり過ぎたもの)は延命できないという定理(というのはいいすぎかもしれないが)がある。プログラミング言語として最もつぶしの効くのが C++ だと信じる私としては、この動きは素直に歓迎したいと思う。

ちなみに VS2005 Express Editon が無償で DL 可能になっているが、以下の内容を実際に走らせてまではいない。私が基本的に VC よりも BCB 使いということもあるが、MFC/ATL を含まないため別途 Platform SDK が必要であるなど、手順が面倒そうなためである。

2007.2.9 補足

念のため補足しておくと C++/CLI は、あくまでも .net Framework に対する C++ 用インタフェースであるため、あくまでも実行は CLR を介して行われる。そのためパフォーマンスは期待できない。

抄録

47-48

ref 修飾子を付与してクラスや構造体を宣言するとガベージコレクション(GC)の対象となる。GC の対象となったオブジェクトは明示的な delete が不要で、new の代わりに gcnew を使う。ガベージコレクションはオブジェクトがスコープを抜けた時点で行われ、もちろんデストラクタも呼び出される。また、GC 使用を明示するために handle 型であることを示す ^ (ハット)をポインタ型の * (アスタリスク)のように使用する。逆に値を直接含むリファレンスでない型(GC の不要な型)であることを明示したい場合は value を付与する。

// ref
ref class X  // GC 対象クラス
{
public:
    int i;
    int getX(){return i;}
};

int main()
{
    X^ px;  // handle型
    px = gcnew X;  // インスタンスの生成
    px->i = 100;
    int x = px->getX();
}
// value
#include "stdafx.h"
using namespace System;

value struct V  // GC 不要の型
{
    int i;
}

int _tmain()
{
    V v1, v2;
    v1.i = 1;
    v2 = v1;
    v2.i = 2;

    return 0;
}

48

interface 修飾子によってインタフェースを独立させ、定義と実装を分離することができる。Java の interface と同じ。

public interface class A
{
    void f(Object o);  // 宣言のみで実装は行えない
}

48-49

列挙型をクラス/構造体として宣言できる。体裁はクラスだが内容を列挙型の値(int)として参照できる。何でもクラスにしておきたい人向けか ?

enum class Days{ SUN=1, MON, TUE, WED, THU, FRI, SAT};

int _tmain()
{
    int x = (int)Days::SUN;  // 1 が入る
}

49-50

イベントドリブンを実装するために、プロパティ宣言のための property、メソッド宣言のための delegate、イベントハンドラ宣言のための event 修飾子が追加されている。要は property は JavaBeans、delegate は委譲メソッド、event はコールバックのそれぞれを仕様として含んだということ。

// property
public ref class C
{
private:
    int i;
public:
    property String^ sp;  // プロパティ
    property int ip  // get/set メソッド
    {
        int get();
        void set(int v)
        {
            i = v;
        }
    }
};

int C::Property_Block::get()  // get() 実装
{
    return i;
}

int main()
{
    C^ c = gcnew C;
    c->sp = "test";
    c->ip = 100;
}
// delegate
public delegate void F(int i);  // 委譲先

ref class A  // 委譲元(委譲元と委譲先の引数は同じ)
{
public:
    void f1(int i)
    {
        Console::WriteLine("f1", i);
    }

    void f2(int i)
    {
        Console::WriteLine("f2", i);
    }

    static void f3(int i)  // 静的メソッド
    {
        Console::WriteLine("f3", i);
    }
};

int main()
{
    A^ a = gcnew A;
    F^ f;  // (このとき f == NULL は保障されるのか ? : 唯野注)

    if(f)  // 未割り当てなので偽
    {
        f(7);
    }

    f = gcnew F(a, &A::f1);  // A::f1() を F として登録
    if(f)
    {
        f(8);
    }

    f += gcnew F(a, &A::f2);  // 追加登録
    f(9);  // f1() と f2() の双方が呼び出される

    f -= gcnew F(a, &A::f1);  // A::f1() の解除

    f->Invoke(10);  // 登録と同時に呼び出す場合

    F^ static_f = gcnew F(&A::f3);  // 静的メソッドを登録
    static_f(11);  // 静的メソッドの呼び出し
}
// event
using namespace System;  // CLR を使う

delegate void ClickEventHandler(int, double);
delegate void DbClickEventHandler(String^);

ref class EventDef  // イベント定義クラス
{
public:
    // イベントハンドラの宣言
    event ClickEventHandler^ OnClick;  // クリック
    event DbClickEventHandler^ OnDbClick;  // ダブルクリック

    void PseudoEvents()
    {
        OnClick(100, 1.2345);
        OnDbClick("Hello");
    }
};

ref class EventRcv  // イベント受信クラス
{
public:
    void OnMyClick(int i, double d)
    {
        Console::WriteLine("OnClick: {0}, {1}", i, d);
    }

    void OnMyDbClick(String^ s)
    {
        Console::WriteLine("OnDbClick: {0}", s);
    }
};

int main()
{
    EventDef^ evtDef = gcnew EventDef();
    EventRcv^ evtRcv = gcnew EventRcv();

    // イベントの登録(複数可能)
    evtDef->OnClick +=
        gcnew ClickEventHandler(evtRcv, &EventRcv::OnClick);
    evtDef->OnDbClick +=
        gcnew DbClickEventHandler(evtRcv, &EventRcv::OnDbClick);

    EvnetDef->PseudoEvents();  // イベントの擬似発生

    // イベントの解除
    evtDef->OnClick -=
        gcnew ClickEventHandler(evtRcv, &EventRcv::OnClick);
    evtDef->OnDbClick -=
        gcnew DbClickEventHandler(evtRcv, &EventRcv::OnDbClick);
}

全文を読まれる場合はログインしてください


Up