C++/CLIをつつく12ープロパティ。データを守ろう。
#include "stdafx.h"
using namespace System;
namespace Sample
{
public ref class Bird
{
public:
//フィールド
String^ Name;
Int32 Age;
//メソッド
void Talk( ) {
Console::WriteLine( "私は{0}。年は{1}だよ。",
this->Name, this->Age);
}
};
}
using namespace Sample;
int main(array< System::String ^ > ^ args)
{
Bird^ b = gcnew Bird() ;
b->Name = "インドリ";
b->Age = 29;
b->Talk( );
b->Name = "ドリィちゃん";
b->Age = -20;
b->Talk( );
Console::WriteLine(
"えぇ~!、凄い年齢詐称だ・・・" );
return 0;
}
ドリィちゃんそこまで年齢を誤魔化さなくても・・・
インドリィちゃん「女性の年齢を聞くな!」
こんな具合にフィールドを直接扱えるようにしてしまったら入力値の妥当性をチェックできない んだ。では入力値をチェックするために値の設定にメソッドを設定してみよう、
#include "stdafx.h"
using namespace System;
namespace Sample
{
public ref class Bird
{
//フィールド
private:
Int32 m_age;
public:
String^ Name;
//メソッド
void Talk( ) {
Console::WriteLine( "私は{0}。年は{1}だよ。", this->Name, m_age);
}
void SetAge( Int32 age ) {
if ( age > 0 ) m_age = age;
}
};
}
using namespace Sample;
int main(array< System::String ^> ^ args)
{
Bird^ b = gcnew Bird() ;
b->Name = "インドリ";
b->SetAge(29);
b->Talk( );
b->Name = "ドリィちゃん";
b->SetAge(-20);
b->Talk( );
Console::WriteLine(
"ドリィちゃん、ボクと同じ年齢なんだね♪" );
return 0;
}
これで年齢にマイナス値を入力したら、その罰として前の人の年齢が表示されるようになるよ。
インドリィちゃん「この屈辱忘れるものかぁぁ」
ビック!ちょっと後がまずいことになるかも・・・それはさておき、フィールドを保護するために一々Set○○、Get○○って 名前のメソッドを作るのは面倒だし見栄えが悪いよね。だからC++/CLIにはもっといい方法が用意されているんだ。早速見てみよう。
#include "stdafx.h"
using namespace System;
namespace Sample
{
public ref class Bird
{
//フィールド
private:
Int32 m_age;
String^ m_name;
public:
property Int32 Age {
Int32 get() { return this->m_age; } //<ーツンツン
void set( Int32 value ) { //<ーツンツン
if ( value > 0 ) m_age = value;
}
}
property String^ Name {
String^ get() { return this->m_name; } //<ーツンツン
void set( String^ value ) { this->m_name = value; } //<ーツンツン
}
//メソッド
void Talk( ) {
Console::WriteLine( "私は{0}。年は{1}だよ。",
this->m_name, this->m_age);
}
};
}
using namespace Sample;
int main(array< System::String ^> ^ args)
{
Bird^ b = gcnew Bird() ;
b->Name = "インドリ";
b->Age = 29;
b->Talk( );
b->Name = "ドリィちゃん";
b->Age = -20;
b->Talk( );
Console::WriteLine(
"ドリィちゃん、ボクと同じ年齢なんだね♪" );
return 0;
}
この構文がプロパティなんだ。この構文を詳しく突付いてみよう。
まずは始めのプロパティの宣言は・・・
property Int32 { プログラム }
プロパティが見える範囲(C++/CLIではまとめて定義)、 ってなっている。これはプロパティの型、 プロパティの名前の三つを指定しているんだ。
プロパティが見える範囲については色々あるから説明は後回しで、型と名前を考えてみよう。 型と名前はもうお馴染だよね?考え方はフィールド(変数)と変わらないピヨ。
propertyキーワード以外のプロパティとフィールドの違いは、
型 get() { プログラム }と
void set(値を表す変数) { プログラム }があるところなんだ。
get()はプロパティの値を取得する部分で、set(値を表す変数)はプロパティの値を設定する部分なんだ。 setの部分だけ注意が必要で代入する値を宣言する必要があるんだ。 それにしても、何故C++/CLIは型を何度も宣言しなくちゃならないんだ? うっしししし、よーし試しにset()の型を変えてやるピヨー。
エラー 1 error C3901: 'get': 戻り値の型 'int' を指定しなければなりませんえっ?コンパイルエラーが出たぞ。そりゃ当たり前といえば当たり前なんだけど、 何でコンパイラがわかっている事を一々書かなければならないんだ? ボクには理解できないピヨ。
コンパイラが分かっている事を書く必要ある?
これは余談なんだけど実はプロパティは全てのオブジェクト指向言語に実装されているわけではないんだ。 それは何故かというと、メソッドでも実現できるから「メソッドで同じことが出来るからいいじゃん」という人がいるからなんだ。 だけどボク個人の意見としてはリフレクションを有効に使うためにはプロパティとメソッドを明確に分けたほうが良いと思うピヨ。
余談おしまい。この記事もおしまい。
追記
これを書いた後でC++/CLIプロパティに凄い機能を発見したピヨ。
C++/CLIでは、省略記法というのがあって、サンプルコードのNameプロパティを、
property String^ Name;で定義できるんだ!しかもフィールドも要らない。これは便利!他の言語にはないよ。文句言ってごめんC++/CLI。見直したよ。