ページ 1 / 1
C++についての質問
Posted: 2010年7月24日(土) 11:24
by シエル
いつもお世話になっております。シエルです。
C++の良さを知って、C++を勉強中なのですが、c++のクラスについて質問があります。
ネットのサンプルを色々見ていると、
下記のようなAとBのヘッダファイルがあり、Bのヘッダファイルの中に
【class A;】というようなコードがありました。
このコードはBのヘッダファイルにおいて、どのような効果があるのでしょうか?
ご教授お願い致します。
ちなみにBのヘッダファイルではAのヘッダファイルのインクルードは行われておりませんでした。
/////A.h///////////////
class A {
public
A();
};
///////////////////////
/////B.h////////////////
class B {
public
B();
};
class A;←こいつのことです!
/////////////////////////
Re:C++についての質問
Posted: 2010年7月24日(土) 11:42
by Poco
クラスAのメンバにクラスBを持たせて、
クラスBのメンバにクラスAを持たせて、
かつ
コンパイルが通る、
ソースを書いてみてください。
その時に、class A;という記述の意義が分かります、多分。
Re:C++についての質問
Posted: 2010年7月24日(土) 11:49
by シエル
ぽこさん。ありがとうございます。
色々試したみたんですが、
class A;という記述は「AのヘッダファイルのクラスAだけをインクルードしている」
というような意味ということでしょうか?
Re:C++についての質問
Posted: 2010年7月24日(土) 11:56
by Poco
コンパイル通せました?
クラスBの中にあるAという識別子がクラスAですよ、っという情報だけを与えています。
クラスAの定義の情報は与えません。
#構造体に関して、同じようなものがC言語でもありますよ。

Re:C++についての質問
Posted: 2010年7月24日(土) 12:08
by シエル
コンパイルは通せました。
>クラスBの中にあるaという変数がクラスAですよ、っという情報だけを与えています。
>クラスAの定義の情報は与えません。
【質問1】
クラスBの中で、
クラス「A」という型が使えるようになるってことですか?
【質問2】
class A;
↑何故こう書くだけで「A.h」というファイルの中のクラスAの情報を見にいけるのでしょうか?
Bのヘッダファイル内ではクラスAの情報は「A.h」の中にあるという情報は与えていませんよね?
【質問3】
なぜ単純にAのヘッダファイルをインクルードせずに、このようなやり方をするのでしょうか?
>#構造体に関して、同じようなものがC言語でもありますよ。
教えていただけるとありがたいです。
質問ばかりですみませんが、よろしくお願いいたします!
Re:C++についての質問
Posted: 2010年7月24日(土) 12:20
by Poco
【質問1】
No。使えません。使うにはクラスAの定義が必要です。
【質問2】
「見に行っていない」と考えるのが自然です。
【質問3】
私が先程シエルさんに提示した、相互参照を行う場合に
ヘッダファイルをインクルードすることは、問題の解決になりません。
Re:C++についての質問
Posted: 2010年7月24日(土) 12:56
by たかぎ
class A; のような不完全宣言を行った場合、Aのポインタや参照であれば使うことができます。
しかし、メンバを参照することも、A型のオブジェクトを生成または解体することもできません。
Re:C++についての質問
Posted: 2010年7月24日(土) 13:37
by シエル
う~ん。頭悪いのでよく分からないですね^^;
下記のようなb.cppがあった場合、Aのインスタンスは作成できなくて、そのメンバの関数も
呼べないってことでしょうか?
/////A.h///////////////
class A {
public
A();
void testa();
};
///////////////////////
/////B.h////////////////
class A;
class B {
A *a;
public
B();
void testb();
};
/////////////////////////
//////B.cpp//////////////
#include "B.h"
void B::testb()
{
a=new A;
a.testa();←このような呼び出し方は出来ないということでしょうか?
}
/////////////////////////
Re:C++についての質問
Posted: 2010年7月24日(土) 13:44
by たかぎ
> 下記のようなb.cppがあった場合、Aのインスタンスは作成できなくて、そのメンバの関数も
> 呼べないってことでしょうか?
そういうことです。
Re:C++についての質問
Posted: 2010年7月24日(土) 13:48
by シエル
う~ん;
それではclass A;は何の役に立つのでしょうか?
どういうときに使うのでしょうか?
Re:C++についての質問
Posted: 2010年7月24日(土) 13:53
by softya
ヘッダのインクルードに優先順位が必要になったり、お互いにクラスを参照していた場合には問題が起こりますので、それを避ける目的で使います。あと、無闇なヘッダ内のヘッダインクルードを防ぐ効果もありますね。
下記のように書いたときにエラーが出ない方法を色々試してみると分かります。
/////A.h////////////////
class A
{
public:
A(void);
~A(void);
B *b;
};
/////B.h////////////////
class B
{
public:
B(void);
~B(void);
A *a;
};
Re:C++についての質問
Posted: 2010年7月24日(土) 13:55
by softya
それと
//////B.cpp//////////////
#include "B.h"
#include "A.h"
void B::testb()
{
a=new A;
a.testa();←これならOK
}
/////////////////////////
ためしてみてください。

Re:C++についての質問
Posted: 2010年7月24日(土) 13:59
by Poco
> それではclass A;は何の役に立つのでしょうか?
> どういうときに使うのでしょうか?
相互参照する2つのクラスをコンパイルできたんですよね?
class A;やclass B;のどちらか、もしくは両方を削除してみれば分かりますよ。
Re:C++についての質問
Posted: 2010年7月24日(土) 14:06
by softya
ぽこさんの件と合わせと補足します。
もし
class A;
class B;
という書き方を知らなかったら、どうやって書きますか?
下記のものに
class A;
class B;
という書き方を使わずにエラーをなくしてみてください。
/////A.h////////////////
class A
{
public:
A(void);
~A(void);
B *b;
};
/////B.h////////////////
class B
{
public:
B(void);
~B(void);
A *a;
};
Re:C++についての質問
Posted: 2010年7月24日(土) 14:11
by たかぎ
> それではclass A;は何の役に立つのでしょうか?
> どういうときに使うのでしょうか?
相互参照というのはどちらかといえば特殊なケースです。
例えば、<stdio.h>のFILE型を考えてみてください。
class FILE;
FILE* fopen(const char*, const char*);
int fclose(FILE*);
int fgetc(FILE*);
int fputc(int c, FILE*);
int fputs(const char*, FILE*);
char* fgets(char*, int, FILE*);
...
のように、FILE型のメンバにアクセスすることも、FILE型の生成・解体を直接行うこともできないけれども、十分意味のある機能を提供できますよね。
注)実際のFILE型はオブジェクト型でなければならないので、上記のような不完全型では要件を満たしません。
Re:C++についての質問
Posted: 2010年7月24日(土) 14:19
by シエル
たかぎさん、softyaさん、ぽこさんありがとうございます!分かったかもしれません!
class A;
class B;
という書き方を使わずに対応しようとすると、お互いのヘッダファイルをインクルード
しないといけなくなり、お互いにインクルードし続けてしまう状態が発生するということですかね?
だから、相手のクラスのポインタを定義するにはclass A;という書き方をして、Aという識別子が
クラスAであることを表して変数を定義するしかないと。
もしそうだとすると、下記のB.hはA.hをインクルードしていないのに、
class Aと書くだけで、なぜAというクラスの情報がA.hの中にあるということを認識してくれるのでしょうか?
なんか未定義エラーになってもおかしくないような気がするのですが。
コンパイラが勝手に探してくれると思っとけばいいですかね?
/////B.h////////////////
class A;
class B {
A *a;
public
B();
void testb();
};
/////////////////////////
Re:C++についての質問
Posted: 2010年7月24日(土) 14:25
by Poco
> もしそうだとすると、下記のB.hはA.hをインクルードしていないのに、
> class Aと書くだけで、なぜAというクラスの情報がA.hの中にあるということを認識してくれるのでしょうか?
> なんか未定義エラーになってもおかしくないような気がするのですが。
> コンパイラが勝手に探してくれると思っとけばいいですかね?
違います。
認識もしませんし、探索もしません。
たかぎさんが
「class A; のような不完全宣言を行った場合、Aのポインタや参照であれば使うことができます。
しかし、メンバを参照することも、A型のオブジェクトを生成または解体することもできません。」
と書かれていますが、これが「何故できるのか」、「何故できないのか」を
よ~く考えてください。
出来ないことはクラスの定義に関する情報(ヘッダファイルに記述されている情報)がないから
できないのです。

Re:C++についての質問
Posted: 2010年7月24日(土) 14:59
by シエル
よ~~~~~~~~く考えました。なんとなく分かりました。ぽこさんありがとうございます。
class A;
↑つまりこう書くと「中身がないクラス」を作ったことになる。つまり不完全なクラス。
でもクラス自体は作れてるから、そのクラスのポインタは使える。
でも最終的には完全な状態のクラスAのメンバを呼び出して使用したいから、
softyaさんが提示してくだった下記コードのようにA.hを取り込むことによって、
クラスAのメンバが完全に定義されたことになり、クラスAのメンバを呼び出して
使用できるようになるというわけですね・・!
合ってますでしょうか?
//////B.cpp//////////////
#include "B.h"
#include "A.h"
void B::testb()
{
a=new A;
a.testa();←これならOK
}
/////////////////////////
Re:C++についての質問
Posted: 2010年7月24日(土) 15:07
by Poco
> class A;
> ↑つまりこう書くと「中身がないクラス」を作ったことになる。つまり不完全なクラス。
> でもクラス自体は作れてるから、そのクラスのポインタは使える。
> でも最終的には完全な状態のクラスAのメンバを呼び出して使用したいから、
> softyaさんが提示してくだった下記コードのようにA.hを取り込むことによって、
> クラスAのメンバが完全に定義されたことになり、クラスAのメンバを呼び出して
> 使用できるようになるというわけですね・・!
> 合ってますでしょうか?
合っています。
コンパイラの気持ちになれば、
「Aってのがクラス名ってのはわかるけどさぁ、Aのメンバがさっぱりわからないから、
コンストラクタ呼出(生成)やメンバ関数呼び出しを行うコード書かれても、
それが正しい記述か判断できないよ。」
ってことです。
----追記
ようやくプログラマになれた。
先は長いね。。

Re:C++についての質問
Posted: 2010年7月24日(土) 15:16
by シエル
合ってましたか!良かったです!
かなり考えて理解できたので、忘れないと思います。
今回の質問は非常に勉強になりました。
ぽこさん、softyaさん、たかぎさん、暑い中どうもありがとうございました!
本当に助かりました!
これにて解決にさせていただきます!
Re:C++についての質問
Posted: 2010年7月24日(土) 15:23
by Poco
> ぽこさん、softyaさん、たかぎさん、暑い中どうもありがとうございました!
解決できて何よりです。
ホント暑いですよね。西日が差すから外より暑い。。。