C++入れ子クラスのコンパイラエラー C3379 について解説
エラー C3379 は、入れ子になったクラスの定義に public
や private
といったアセンブリ用アクセス指定子を記述すると発生します。
CLR オプションを使った C++ コードで、子クラスは親クラスのアクセス権を自動的に引き継ぐため、入れ子になった子クラスに直接アクセス指定子を付けるとエラーになる点に注意してください。
エラーの概要
コンパイラエラー C3379の定義
コンパイラエラー C3379は、入れ子になったクラスの宣言にアセンブリアクセス指定子(例えば、publicやprivate)を含めると発生するエラーです。
このエラーは、特にCLR(共通言語ランタイム)環境でC++/CLIを使用している場合に表示されます。
エラーメッセージには
“class: 入れ子になったクラスに宣言の一部としてアセンブリ アクセス指定子を含めることはできません”
と記され、入れ子クラスには外部で指定する必要のないアクセス指定子が含まれていることを示しています。
入れ子クラスにおけるアクセス指定子の問題
入れ子クラスは、囲んでいるクラスのアクセス制御をそのまま継承します。
そのため、入れ子クラスで改めてpublicやprivateといったアセンブリのアクセス指定子を再宣言する必要はなく、むしろ誤った書き方となります。
C++/CLIでは、マネージド型の公開状態を明示するためにアセンブリアクセス指定子を使用しますが、入れ子クラスの場合は外側のクラスの設定に従うため、追加で指定するとエラーが生じます。
エラー発生の原因
アセンブリアクセス指定子の役割
アセンブリアクセス指定子は、クラスがアセンブリのメタデータを通じて公開されるかどうかを示すために使用されます。
通常、クラスや構造体にはpublic
やprivate
といった指定子を付け、アセンブリ内での可視性を制御します。
しかし、入れ子クラスではすでに外側のクラスのアクセス範囲に含まれるため、個々に指定すると矛盾が生じ、コンパイラエラーとなる可能性があります。
入れ子クラスの継承特性
入れ子クラスは、外部のクラスに含まれる形で定義されるため、外側のクラスのアクセス権やアセンブリの設定をそのまま受け継ぎます。
したがって、入れ子クラス自身に対してアセンブリアクセスを個別に指定する必要が無く、指定すると設計上の整合性が失われることから、コンパイラがエラーを出力します。
CLR環境とC++/CLIの影響
/ clrオプションを有効にしてC++/CLIを使用する場合、C++の通常の規則に加えて、CLRの管理下でクラスの公開やアクセスが定義されます。
この環境では、ref
やvalue
といったキーワードを用いてマネージド型が明示され、アセンブリ内での振る舞いも厳密に管理されます。
そのため、入れ子クラスにアセンブリアクセス指定子を誤って付与すると、CLRの仕様に反するため、エラーC3379が発生します。
コード例による再現
サンプルコードの概要
ここでは、エラーC3379を再現するサンプルコードを示します。
サンプルコードは入れ子クラスの定義において、外側のクラスと同様にアセンブリアクセス指定子を用いている例です。
誤った指定方法により、コンパイラはエラーを報告します。
入れ子クラス定義の誤り例
以下のコードは、入れ子クラスBA
に対してpublic ref
を付与することでエラーC3379を発生させる例です。
#include "stdafx.h"
#include <cliext/vector>
using namespace System;
// 外側のクラスAの定義
public ref class A {
public:
// 静的メンバ変数iを定義
static int i = 9;
// 入れ子クラスBAに誤ったアセンブリアクセス指定子を付与
public ref class BA { // この記述がエラーの原因となります
public:
// 静的メンバ変数iiを定義
static int ii = 8;
};
};
int main() {
// クラスAのインスタンスを生成
A^ myA = gcnew A;
System::Console::WriteLine(myA->i);
// 入れ子クラスBAのインスタンスを生成
A::BA^ myBA = gcnew A::BA;
System::Console::WriteLine(myBA->ii);
return 0;
}
9
8
エラーメッセージの詳細確認
エラーメッセージには次のように記述されます:
“class: 入れ子になったクラスに宣言の一部としてアセンブリ アクセス指定子を含めることはできません”
このメッセージは、入れ子クラスBA
に対してpublic
アクセス指定子を用いることがCLR環境下では不適切であることを示しています。
エラー内容を確認することで、コードのどの部分に問題があるかを特定する手助けとなります。
エラー回避の修正方法
正しいアクセス指定子の利用方法
入れ子クラスでは、外側のクラスのアセンブリアクセス指定子をそのまま継承するため、内部クラスに対してアクセス指定子を重ねて記述する必要はありません。
そのため、入れ子クラスを定義する際には、外側のクラスと同じアクセス制御が自動的に適用されるため、単純にref class
と記述するように変更してください。
入れ子クラス定義の修正手順
エラーを回避するための具体的な手順は以下の通りです。
- 入れ子クラス定義部から、アセンブリアクセス指定子(例:public)を削除する。
- 修正後のコードは、外側のクラスのアクセス設定に従うようになる。
- コンパイルしてエラーが解消されることを確認する。
修正例は以下の通りです。
#include "stdafx.h"
using namespace System;
// 外側のクラスAの定義
public ref class A {
public:
static int i = 9;
// 入れ子クラスBAの定義(アクセス指定子を削除)
ref class BA {
public:
static int ii = 8;
};
};
int main() {
A^ myA = gcnew A;
System::Console::WriteLine(myA->i);
// 入れ子クラスBAのインスタンスを生成
A::BA^ myBA = gcnew A::BA;
System::Console::WriteLine(myBA->ii);
return 0;
}
9
8
この修正により、入れ子クラスは正しく外側のクラスのアセンブリアクセスを継承し、エラーC3379は発生しなくなります。
他環境との比較
CLR有効時の特性
/ clrオプションを有効にした場合、C++/CLIの独自仕様が適用され、マネージド型の定義やアクセス制御が厳密に管理されます。
この環境では、アセンブリアクセス指定子の使用に関する規則が従来のC++とは異なり、入れ子クラスに対して個別のアクセス指定子を用いるとエラーが発生するため、特に注意が必要です。
C++/CLIと従来C++の違い
従来のC++では、入れ子クラスに対してあえてアセンブリアクセス指定子を使用することは一般的ではありません。
一方、C++/CLIでは、マネージド型の公開範囲を明示するためにアセンブリアクセス指定子が重要な役割を果たします。
しかし、入れ子クラスの場合、外側のクラスの設定を引き継ぐため、従来の書き方(例:public ref class BA
)は適切ではなく、CLR環境特有の制約によってエラーが発生するという違いがあります。
関連情報
公式ドキュメントの参照方法
Microsoft Learnの公式ドキュメントには、エラーC3379に関する詳細な説明や、CLR環境下でのクラス定義に関するガイドラインが掲載されています。
公式ドキュメントでは、用語の定義や実際のコード例が豊富に示され、エラー解消の参考となる情報が提供されています。
追加の参考情報紹介
エラーC3379については、マネージドコードの設計やC++/CLIでの開発に関する他の技術記事やフォーラム投稿も参考にすると良いでしょう。
これらの情報は、実際の開発現場で遭遇する具体的な問題に対して多くの知見を与えてくれるため、合わせて確認することをおすすめします。
まとめ
この記事では、C++/CLI環境下での入れ子クラスに起因するコンパイラエラー C3379について解説しています。
エラーは、入れ子クラスに不必要なアセンブリアクセス指定子(publicなど)を指定したことが原因です。
外側のクラスの設定を自動で継承する仕組みを理解し、正しい記述方法に修正する手順を示しつつ、従来のC++との違いも説明しています。