入れ子クラスの先行宣言

[戻る]
谷岡 2004/09/03(金) 14:46:30
こんにちは。谷岡と申します。

class A {
  public:
  struct B {
  };
};
のようにクラスをファイルA.hに宣言して、別のヘッダーファイルに
A.hをインクルードせずに構造体A::Bを先行宣言したいのですが
どのような表記になるのでしょうか?

class A;
struct A::B;
のよう宣言してVC++.NET2003でコンパイルすると二行目で

error C2027: 認識できない型 'A' が使われています。
error C2079: 'B' が 未定義の class 'A' で使用しています。
というようなエラーが出ます。

以上、よろしくお願いします。

PATIO 2004/09/03(金) 17:53:25
普通に考えるとこれは無理な気がします。
先行宣言は使う側がクラス構造を知る必要が無い場合だけに使用可能ですよね。
例えば、クラスの中でclass Aのポインタを宣言したい時は使えますが、
class Aのインスタンスと起こす場合は使えません。
(ポインタ宣言の場合、Aがクラスであるとわかっていれば、
 クラス構造まで必要ありませんから)

もし、sturct A::Bとしてしまうとコンパイラはこの時点でclass Aの構造を知る
必要が出てくると思います。
だから、エラーになったのではないでしょうか。

もし出来ると言う話なら私も知りたいです。

PATIO 2004/09/03(金) 17:54:33
タイプミスです。

誤)
class Aのインスタンスと起こす場合は使えません。

正)
class Aのインスタンスを起こす場合は使えません。

谷岡 2004/09/04(土) 15:46:27
PATIOさんありがとうございます。

コンパイラにAという名前のクラスの中にBという名前の構造体が宣言されて
いることを教えれば原理的にコンパイル可能のような気がします。
普通にAを先行宣言した場合は現在の名前空間にAという名前のクラスがある
ことをコンパイラに教えているだけなので入れ子クラスでも考え方は変わら
ないと思います。

言語の仕様として入れ子クラスの先行宣言ができないのであれば、入れ子ク
ラスの欠点なんでしょうかね?A_Bのような名前の非入れ子構造体にしても
入れ子構造とできることは変わらないのですが、Aとの関連が強いことを表現
するために入れ子にしています。

PATIO 2004/09/06(月) 11:16:06
これを許してしまうとクラス定義が複数個所で存在する事になって
一意性が失われませんか?

もし本来のクラス宣言と食い違っていたら?

コンパイラがそれをチェックするためにはクラス宣言そのものを
参照出来る事が条件になるはずです。

コンパイラは基本的にコーダーを信頼するのではなくて
コーダーを疑ってかかるように出来ていると思います。

Aがクラスであることがわかれば十分である場合、
クラス宣言の中身は問題になりませんが、
Aの中にstruct Bがあると書かれれば、クラス宣言のチェックをしないわけには
いかないと思いますよ。

Bosscat 2004/09/06(月) 12:28:22
横槍、失礼^^

> コンパイラにAという名前のクラスの中にBという名前の構造体が宣言されて
> いることを教えれば原理的にコンパイル可能のような気がします。

確かに、原理的には不可能ではないですね。
ただ、出来ても嬉しくありません。

仮宣言( class A; )の用途は
   . . . .
「Aの内部構造に興味は無いけど利用したい」

ですから、内部構造が必要なら#includeすれば良いのです。
(モジュール結合度を下げる事は出来ないのですから・・・)

> Aとの関連が強いことを表現するために入れ子にしています。
外部宣言するほどの重要度ならばnamespaceを切った方が良いでしょう。

基本的に入れ子によるI/Fクラスなどは、
「他クラスメンバ」or「グローバル」等にはしないものです。
(もちろんポインタの意)

私が入れ子クラスを使う場合は以下の場合位です。
・enum{ERROR = 0,SUCCESS = 1}; // 関数戻り値定義
・内部利用オンリー(protected)
・一時的な用途限定の関数I/F
(リスト構造のクラスにおける取得関数等でのindex,data のセット 等)

以上

谷岡 2004/09/07(火) 21:07:48
[[解決]]
PATIOさん、Bosscatさん、アドバイスありがとうございました。

先行宣言にこだわったのは単にヘッダーファイルには可能な限り他のファイルを
インクルードしたくなかったからです。これにはコンパイル時間を節約する以外の
意味はありません。C++の仕様では入れ子クラスの先行宣言はできなさそうなので
このようなクラスが必要なときはヘッダーファイルをインクルードすることにし
ました。

先行宣言がどうしても必要な場合はクラスが循環依存しているときぐらいだと思
いますが、その場合でも先行宣言は1つのヘッダーファイル内でよいので入れ子
クラスを先行宣言しなければならない状況はめったにないかもしれません。

古いスレッドには追加発言できません。