Практическое руководство. Использование свойств в C++/CLI
В этой статье показано, как использовать свойства в C++/CLI.
Базовые свойства
Для базовых свойств , которые просто назначают и извлекают член частных данных, вам не нужно явно определять функции метода получения и задания доступа, так как компилятор автоматически предоставляет их при указании только типа данных свойства. Этот код демонстрирует базовое свойство:
// SimpleProperties.cpp
// compile with: /clr
using namespace System;
ref class C {
public:
property int Size;
};
int main() {
C^ c = gcnew C;
c->Size = 111;
Console::WriteLine("c->Size = {0}", c->Size);
}
c->Size = 111
Статические свойства
В этом примере кода показано, как объявить и использовать статическое свойство. Статическое свойство может получить доступ только к статическим членам своего класса.
// mcppv2_property_3.cpp
// compile with: /clr
using namespace System;
ref class StaticProperties {
static int MyInt;
static int MyInt2;
public:
static property int Static_Data_Member_Property;
static property int Static_Block_Property {
int get() {
return MyInt;
}
void set(int value) {
MyInt = value;
}
}
};
int main() {
StaticProperties::Static_Data_Member_Property = 96;
Console::WriteLine(StaticProperties::Static_Data_Member_Property);
StaticProperties::Static_Block_Property = 47;
Console::WriteLine(StaticProperties::Static_Block_Property);
}
96
47
Индексируемые свойства
Индексированные свойства обычно предоставляют структуру данных, доступ к которому обращается с помощью оператора подстрочного индекса.
При использовании индексированного свойства по умолчанию можно получить доступ к структуре данных, указав имя класса, но при использовании определяемого пользователем индексированного свойства необходимо указать имя свойства для доступа к структуре данных.
Сведения о том, как использовать индексатор, написанный на C#, см. в разделе "Практическое руководство. Использование индексатора C# (C++/CLI)".
В этом примере кода показано, как использовать свойства индексированного индекса по умолчанию и определяемые пользователем:
// mcppv2_property_2.cpp
// compile with: /clr
using namespace System;
public ref class C {
array<int>^ MyArr;
public:
C() {
MyArr = gcnew array<int>(5);
}
// default indexer
property int default[int] {
int get(int index) {
return MyArr[index];
}
void set(int index, int value) {
MyArr[index] = value;
}
}
// user-defined indexer
property int indexer1[int] {
int get(int index) {
return MyArr[index];
}
void set(int index, int value) {
MyArr[index] = value;
}
}
};
int main() {
C ^ MyC = gcnew C();
// use the default indexer
Console::Write("[ ");
for (int i = 0 ; i < 5 ; i++) {
MyC[i] = i;
Console::Write("{0} ", MyC[i]);
}
Console::WriteLine("]");
// use the user-defined indexer
Console::Write("[ ");
for (int i = 0 ; i < 5 ; i++) {
MyC->indexer1[i] = i * 2;
Console::Write("{0} ", MyC->indexer1[i]);
}
Console::WriteLine("]");
}
[ 0 1 2 3 4 ]
[ 0 2 4 6 8 ]
В следующем примере показано, как вызвать индексатор по умолчанию с помощью this
указателя.
// call_default_indexer_through_this_pointer.cpp
// compile with: /clr /c
value class Position {
public:
Position(int x, int y) : position(gcnew array<int, 2>(100, 100)) {
this->default[x, y] = 1;
}
property int default[int, int] {
int get(int x, int y) {
return position[x, y];
}
void set(int x, int y, int value) {}
}
private:
array<int, 2> ^ position;
};
В этом примере показано, как указать DefaultMemberAttribute индексатор по умолчанию:
// specify_default_indexer.cpp
// compile with: /LD /clr
using namespace System;
[Reflection::DefaultMember("XXX")]
public ref struct Squares {
property Double XXX[Double] {
Double get(Double data) {
return data*data;
}
}
};
Следующий пример использует метаданные, созданные в предыдущем примере.
// consume_default_indexer.cpp
// compile with: /clr
#using "specify_default_indexer.dll"
int main() {
Squares ^ square = gcnew Squares();
System::Console::WriteLine("{0}", square[3]);
}
9
Виртуальные свойства
В этом примере кода показано, как объявлять и использовать виртуальные свойства:
// mcppv2_property_4.cpp
// compile with: /clr
using namespace System;
interface struct IEFace {
public:
property int VirtualProperty1;
property int VirtualProperty2 {
int get();
void set(int i);
}
};
// implement virtual events
ref class PropImpl : public IEFace {
int MyInt;
public:
virtual property int VirtualProperty1;
virtual property int VirtualProperty2 {
int get() {
return MyInt;
}
void set(int i) {
MyInt = i;
}
}
};
int main() {
PropImpl ^ MyPI = gcnew PropImpl();
MyPI->VirtualProperty1 = 93;
Console::WriteLine(MyPI->VirtualProperty1);
MyPI->VirtualProperty2 = 43;
Console::WriteLine(MyPI->VirtualProperty2);
}
93
43
Абстрактные и запечатанные свойства
Хотя абстрактные и запечатанные ключевые слова указаны как допустимые в спецификации ECMA C++/CLI, для компилятора Microsoft C++ их нельзя указать в тривиальных свойствах, а также в объявлении свойства нетривиального свойства.
Чтобы объявить запечатаемое или абстрактное свойство, необходимо определить нетривиальное свойство, а затем указать abstract
sealed
ключевое слово для функций получения и задания доступа.
// properties_abstract_sealed.cpp
// compile with: /clr
ref struct A {
protected:
int m_i;
public:
A() { m_i = 87; }
// define abstract property
property int Prop_1 {
virtual int get() abstract;
virtual void set(int i) abstract;
}
};
ref struct B : A {
private:
int m_i;
public:
B() { m_i = 86; }
// implement abstract property
property int Prop_1 {
virtual int get() override { return m_i; }
virtual void set(int i) override { m_i = i; }
}
};
ref struct C {
private:
int m_i;
public:
C() { m_i = 87; }
// define sealed property
property int Prop_2 {
virtual int get() sealed { return m_i; }
virtual void set(int i) sealed { m_i = i; };
}
};
int main() {
B b1;
// call implementation of abstract property
System::Console::WriteLine(b1.Prop_1);
C c1;
// call sealed property
System::Console::WriteLine(c1.Prop_2);
}
86
87
Многомерные свойства
Для определения методов доступа к свойствам, которые принимают нестандартное число параметров, можно использовать многомерные свойства.
// mcppv2_property_5.cpp
// compile with: /clr
ref class X {
double d;
public:
X() : d(0) {}
property double MultiDimProp[int, int, int] {
double get(int, int, int) {
return d;
}
void set(int i, int j, int k, double l) {
// do something with those ints
d = l;
}
}
property double MultiDimProp2[int] {
double get(int) {
return d;
}
void set(int i, double l) {
// do something with those ints
d = l;
}
}
};
int main() {
X ^ MyX = gcnew X();
MyX->MultiDimProp[0,0,0] = 1.1;
System::Console::WriteLine(MyX->MultiDimProp[0, 0, 0]);
}
1.1
Перегрузка методов доступа к свойствам
В следующем примере показано, как перегружать индексированные свойства.
// mcppv2_property_6.cpp
// compile with: /clr
ref class X {
double d;
public:
X() : d(0.0) {}
property double MyProp[int] {
double get(int i) {
return d;
}
double get(System::String ^ i) {
return 2*d;
}
void set(int i, double l) {
d = i * l;
}
} // end MyProp definition
};
int main() {
X ^ MyX = gcnew X();
MyX->MyProp[2] = 1.7;
System::Console::WriteLine(MyX->MyProp[1]);
System::Console::WriteLine(MyX->MyProp["test"]);
}
3.4
6.8