LoginSignup
23
33

More than 3 years have passed since last update.

忘れっぽい僕のためのC++/CLIチートシート

Last updated at Posted at 2018-10-12

目的

たまーにC++/CLI (Common Language Infrastructure) を使うことがあるが、たまにしか使わない。
なので、使おうとするたびに忘れて、思い出すのに手間取る記法やらを、他でもない自分のためにまとめておく。
C++/CLIが初めてという方は、以下のサイトで丁寧にわかりやすく解説されているので、そちらを参照されたい。
C++/CLI入門 - WisdomSoft

プロジェクトの設定

スクリーンショットはVS2017のもの。
ネイティブコードと混ぜるときは「共通言語ランタイム サポート(/clr)」を選ぶ。

image.png

Hello, World!

#using <mscorlib.dll>

int main(int argc, char **argv)
{
    System::Console::WriteLine("Hello, world!");

    return 0;
}

マネージドクラス

クラス定義とインスタンス生成

ref class でクラス定義。インスタンスの変数は^をつけ、インスタンス生成にはgcnewを用いる。

public ref class ClassA
{
public:
    int field;
    void showField()
    {
        System::Console::WriteLine("field is " + field);
    }
};

int main(int argc, char **argv)
{
    ClassA^ a = nullptr;    // 無効な参照はnullptrキーワードで表す
    a = gcnew ClassA();
    a->field = 22;
    a->showField();     // field is 22

    return 0;
}

ネイティブクラスのメンバ変数としてマネージドクラスの参照を持つ

ネイティブクラスのメンバ変数として、上記のマネージドクラスClassAのインスタンスへの参照を持たせるには、gcrootを使う。

#include <vcclr.h>

// ClassAの定義は先述と同様のため省略

public class NativeClass
{
public:
    void setClassA(ClassA^ a)
    {
        this->classA = a;
    }

    ClassA^ getClassA()
    {
        return this->classA;
    }

    void showMsg()
    {
        this->classA->showField();
    }

private:
    gcroot<ClassA^> classA;
};

int main(int argc, char **argv)
{
    NativeClass nc;
    ClassA^ a = gcnew ClassA();
    a->field = 44;
    nc.setClassA(a);
    nc.showMsg();    // field is 44

    return 0;
}

プロパティ

下記の例でNameはトリビアルプロパティ(Nameを格納するためのprivateフィールドが自動生成される)。
Ageはカスタムのゲッター・セッターを定義している。

public ref class User
{
private:
    int _Age;
public:
    property System::String^ Name;
    property int Age
    {
        int get()
        {
            return this->_Age;
        }
        void set(int value)
        {
            if (value >= 0)
            {
                this->_Age = value;
            }
        }
    }
};

上記のように定義したUserクラスをC#から利用した例が以下。NewtonsoftJson.JsonConvertにもかけられる。

static void Main(string[] args)
{
    CLILib.User user = new CLILib.User();
    user.Name = "John";
    user.Age = 29;
    System.Console.WriteLine("Name: {0}, Age: {1}", user.Name, user.Age);
    // Name: John, Age: 29

    user.Age = -3;
    System.Console.WriteLine("Name: {0}, Age: {1}", user.Name, user.Age);
    // Name: John, Age: 29
    // Ageのsetの値チェックに引っかかるため、負の値は代入されない。

    string json = Newtonsoft.Json.JsonConvert.SerializeObject(user);
    System.Console.WriteLine(json);
    // {"Age":29,"Name":"John"}
}

マネージ配列

int main(int argc, char **argv)
{
    cli::array<int>^ iAry1 = gcnew cli::array<int>(5);  // サイズ5の配列。
    cli::array<int>^ iAry2 = gcnew cli::array<int>(3) { 2, 4, 6 };  // 要素を初期化
    cli::array<int>^ iAry3 = { 10, 20, 30 };    // gcnew~は省略可能

    auto printArray = [](cli::array<int>^ a)
    {
        // イテレートは正直にfor文を使う。
        for (int i = 0, ii = a->Length; i < ii; i++)
        {
            System::Console::Write(a[i] + " ");
        }
        System::Console::WriteLine();
    };

    printArray(iAry1);  // 0 0 0 0 0
    printArray(iAry2);  // 2 4 6
    printArray(iAry3);  // 10 20 30

    return 0;
}

List

int main(int argc, char **argv)
{
    // これを書くとList変数宣言時の名前空間記述を省略できる。
    using namespace System::Collections::Generic;

    // 生成
    List<int>^ iList = gcnew List<int>();

    // 要素の追加
    iList->Add(10);
    iList->Add(20);
    // 引数に{31, 32, 33}とだけ書くとコンパイルエラー。
    // 明示的にcli::arrayをgcnewする必要がある。
    iList->AddRange(gcnew cli::array<int>(3) { 31, 32, 33 });

    // イテレート。
    for (int i = 0, ii = iList->Count; i < ii; i++)
    {
        System::Console::Write(iList[i] + " ");
    }
    System::Console::WriteLine();

    // 出力:
    // 10 20 31 32 33

    return 0;
}

このとき、リストに対して直接[]でアクセスしようとすると、IntelliSenseにより下図のように「式にはpointer-to-object型またはhandle-to-C++/CLI-array型が必要です」と表示されるが、ビルドは正常に通り、問題なく動作する。

image.png

その他

備忘したい事項が出てきたら随時追記予定。

参考

C++/CLIの入門的な部分:
C++/CLI入門 - WisdomSoft

C++/CLIのマネージドクラスでのプロパティについて:
C++/CLI TIps:プロパティ

23
33
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
33