部分クラス (C++/CX)
部分クラスは、ユーザーがクラス定義の一部を変更するのと同時に、XAML デザイナーなどの自動コード生成ソフトウェアも同じクラスのコードを変更するようなシナリオをサポートする構造体です。 部分クラスを使用することにより、デザイナーがコードを上書きすることを防ぐことができます。 Visual Studio プロジェクトでは、生成されたファイルに partial
修飾子が自動的に適用されます。
構文
部分クラスを定義するには、通常のクラス定義のクラス キーの直前に partial
キーワードを使用します。 partial ref class
などのキーワードは、空白文字を含むコンテキスト キーワードです。 部分定義は、次の構造体でサポートされています。
class
またはstruct
ref class
またはref struct
value class
またはvalue struct
enum
またはenum class
ref interface
、interface class
、interface struct
または__interface
union
この例は、部分的な ref class
を示しています。
partial ref class MyClass {/* ... */};
Contents
部分クラス定義には、 partial
キーワードを省略した場合に完全クラス定義に含めることができるすべてのものを含めることができます。 1 つの例外を除き、これには、基底クラス、データ メンバー、メンバー関数、列挙体、フレンド宣言、および属性など、任意の有効な構造体が含まれます。 また、静的データ メンバーのインライン定義が許可されています。
1 つの例外は、クラス アクセシビリティです。 たとえば、 public partial class MyInvalidClass {/* ... */};
ステートメントはエラーです。 MyInvalidClass の部分クラス定義で使用されるいずれのアクセス指定子も、それ以降の MyInvalidClass の部分クラス定義または完全クラス定義の既定のアクセシビリティに影響しません。
次のコード片は、アクセシビリティを示しています。 最初の部分クラスでは、アクセシビリティがパブリックであるため、 Method1
もパブリックです。 2 番目の部分クラスでは、既定のクラス アクセシビリティがプライベートであるため、 Method2
もプライベートです。
partial ref class N
{
public:
int Method1(); // Method1 is public.
};
ref class N
{
void Method2(); // Method2 is private.
};
宣言
MyClass
などのクラスの部分定義は、MyClass の宣言にすぎません。 つまり、MyClass
という名前を紹介しているだけです。 MyClass
は、クラス定義を必要とする方法では使用できません。たとえば、MyClass
のサイズがわかっている場合や MyClass
の基底クラスまたはメンバーを使用する場合です。 MyClass
は、コンパイラが部分定義ではない MyClass
の定義を検出した場合のみ、定義されていると見なされます。
次の例は、部分クラスの宣言の動作を示しています。 宣言 #1 の後で、MyClass
があたかも事前宣言 ref class MyClass;
として記述されているかのように、このクラスを使用することができます。 宣言 #2 は、宣言 #1 と同じです。 宣言 #3 はクラスへの前方宣言であるため有効です。 ただし、宣言 #4 は、
MyClass
が完全に定義されていません。
宣言 #5 は partial
キーワードを使用しません。また、この宣言は、MyClass
を完全に定義します。 その結果、宣言 #6 は有効です。
// Declaration #1
partial ref class MyClass {};
// Declaration #2
partial ref class MyClass;
// Declaration #3
MyClass^ pMc; // OK, forward declaration.
// Declaration #4
MyClass mc; // Error, MyClass is not defined.
// Declaration #5
ref class MyClass { };
// Declaration #6
MyClass mc; // OK, now MyClass is defined.
数字と順序
1 つのクラスの完全定義には、0 個またはそれ以上の部分クラス定義を持たせることができます。
1 つのクラスに関する部分クラス定義のそれぞれは、構文上、そのクラスに関する 1 つの完全定義より前に記述する必要がありますが、そのクラスの事前宣言より前に記述する必要はありません。 クラスの完全定義がない場合、部分クラス宣言に指定できるのは事前宣言のみです。
class
や struct
などのすべてのクラス キーは一致する必要があります。 たとえば、 partial class X {}; struct X {};
という名前のみ説明します。
次の例は、数字と順序を示しています。 最後の部分宣言は、クラスが既に定義されているため失敗します。
ref class MyClass; // OK
partial ref class MyClass{}; //OK
partial ref class MyClass{}; // OK
partial ref class MyClass{}; // OK
ref class MyClass{}; // OK
partial ref class MyClass{}; // C3971, partial definition cannot appear after full definition.
完全定義
クラス X の完全定義の点で、動作は、X の定義にすべての基底クラスやメンバーなどが、部分クラスで検出および定義されている順序で宣言されている場合のようになります。 つまり、部分クラスの内容は、クラスの完全定義の点で記述されているかのように処理されます。また名前参照および他の言語規則は、部分クラスの内容がその場所に記述されているかのように、クラスの完全定義の点で適用されます。
次の 2 つのコード例には、同じ意味と効果があります。 最初の例は部分クラスを使用し、2 番目の例は部分クラスを使用しません。
ref class Base1 { public: property int m_num; int GetNumBase();};
interface class Base2 { int GetNum(); };
interface class Base3{ int GetNum2();};
partial ref class N : public Base1
{
public:
/*...*/
};
partial ref class N : public Base2
{
public:
virtual int GetNum();
// OK, as long as OtherClass is
//declared before the full definition of N
void Method2( OtherClass^ oc );
};
ref class OtherClass;
ref class N : public Base3
{
public:
virtual int GetNum2();
};
ref class OtherClass;
ref class N : public Base1, public Base2, public Base3
{
public:
virtual int GetNum();
virtual int GetNum2();
private:
void Method2(OtherClass^ oc);
};
テンプレート
部分クラスをテンプレートとして指定することはできません。
制限
部分クラスが、1 つの翻訳単位の範囲を越えることはできません。
partial
キーワードは、 ref class
キーワードまたは value class
キーワードと組み合わせた場合のみサポートされます。
例
次の例では、2 つのコード ファイルにまたがって Address
クラスを定義しています。 デザイナーは Address.details.h
を変更し、ユーザーは Address.h
を変更します。 最初のファイルのクラス定義のみ、 partial
キーワードを使用します。
// Address.Details.h
partial ref class Address
{
private:
Platform::String^ street_;
Platform::String^ city_;
Platform::String^ state_;
Platform::String^ zip_;
Platform::String^ country_;
void ValidateAddress(bool normalize = true);
};
// Address.h
#include "Address.details.h"
ref class Address
{
public:
Address(Platform::String^ street, Platform::String^ city, Platform::String^ state,
Platform::String^ zip, Platform::String^ country);
property Platform::String^ Street { Platform::String^ get(); }
property Platform::String^ City { Platform::String^ get(); }
property Platform::String^ State { Platform::String^ get(); }
property Platform::String^ Zip { Platform::String^ get(); }
property Platform::String^ Country { Platform::String^ get(); }
};