C++についての質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
シエル

C++についての質問

#1

投稿記事 by シエル » 15年前

いつもお世話になっております。シエルです。
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;←こいつのことです!
/////////////////////////

Poco

Re:C++についての質問

#2

投稿記事 by Poco » 15年前

クラスAのメンバにクラスBを持たせて、
クラスBのメンバにクラスAを持たせて、
かつ
コンパイルが通る、
ソースを書いてみてください。
その時に、class A;という記述の意義が分かります、多分。

シエル

Re:C++についての質問

#3

投稿記事 by シエル » 15年前

ぽこさん。ありがとうございます。

色々試したみたんですが、
class A;という記述は「AのヘッダファイルのクラスAだけをインクルードしている」
というような意味ということでしょうか?

Poco

Re:C++についての質問

#4

投稿記事 by Poco » 15年前

コンパイル通せました?

クラスBの中にあるAという識別子がクラスAですよ、っという情報だけを与えています。
クラスAの定義の情報は与えません。

#構造体に関して、同じようなものがC言語でもありますよ。
画像

シエル

Re:C++についての質問

#5

投稿記事 by シエル » 15年前

コンパイルは通せました。

>クラスBの中にあるaという変数がクラスAですよ、っという情報だけを与えています。
>クラスAの定義の情報は与えません。

【質問1】
クラスBの中で、
クラス「A」という型が使えるようになるってことですか?

【質問2】
class A;
↑何故こう書くだけで「A.h」というファイルの中のクラスAの情報を見にいけるのでしょうか?
Bのヘッダファイル内ではクラスAの情報は「A.h」の中にあるという情報は与えていませんよね?

【質問3】
なぜ単純にAのヘッダファイルをインクルードせずに、このようなやり方をするのでしょうか?

>#構造体に関して、同じようなものがC言語でもありますよ。

教えていただけるとありがたいです。


質問ばかりですみませんが、よろしくお願いいたします!

Poco

Re:C++についての質問

#6

投稿記事 by Poco » 15年前

【質問1】
No。使えません。使うにはクラスAの定義が必要です。

【質問2】
「見に行っていない」と考えるのが自然です。

【質問3】
私が先程シエルさんに提示した、相互参照を行う場合に
ヘッダファイルをインクルードすることは、問題の解決になりません。

たかぎ

Re:C++についての質問

#7

投稿記事 by たかぎ » 15年前

class A; のような不完全宣言を行った場合、Aのポインタや参照であれば使うことができます。
しかし、メンバを参照することも、A型のオブジェクトを生成または解体することもできません。

シエル

Re:C++についての質問

#8

投稿記事 by シエル » 15年前

う~ん。頭悪いのでよく分からないですね^^;
下記のような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++についての質問

#9

投稿記事 by たかぎ » 15年前

> 下記のようなb.cppがあった場合、Aのインスタンスは作成できなくて、そのメンバの関数も
> 呼べないってことでしょうか?

そういうことです。

シエル

Re:C++についての質問

#10

投稿記事 by シエル » 15年前

う~ん;
それではclass A;は何の役に立つのでしょうか?
どういうときに使うのでしょうか?

softya

Re:C++についての質問

#11

投稿記事 by softya » 15年前

ヘッダのインクルードに優先順位が必要になったり、お互いにクラスを参照していた場合には問題が起こりますので、それを避ける目的で使います。あと、無闇なヘッダ内のヘッダインクルードを防ぐ効果もありますね。

下記のように書いたときにエラーが出ない方法を色々試してみると分かります。

/////A.h////////////////
class A
{
public:
A(void);
~A(void);

B *b;
};

/////B.h////////////////
class B
{
public:
B(void);
~B(void);

A *a;
};

softya

Re:C++についての質問

#12

投稿記事 by softya » 15年前

それと

//////B.cpp//////////////
#include "B.h"
#include "A.h"

void B::testb()
{
a=new A;
a.testa();←これならOK
}
/////////////////////////

ためしてみてください。 画像

Poco

Re:C++についての質問

#13

投稿記事 by Poco » 15年前

> それではclass A;は何の役に立つのでしょうか?
> どういうときに使うのでしょうか?

相互参照する2つのクラスをコンパイルできたんですよね?
class A;やclass B;のどちらか、もしくは両方を削除してみれば分かりますよ。

softya

Re:C++についての質問

#14

投稿記事 by softya » 15年前

ぽこさんの件と合わせと補足します。
もし
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++についての質問

#15

投稿記事 by たかぎ » 15年前

> それでは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++についての質問

#16

投稿記事 by シエル » 15年前

たかぎさん、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();
};
/////////////////////////

Poco

Re:C++についての質問

#17

投稿記事 by Poco » 15年前

> もしそうだとすると、下記のB.hはA.hをインクルードしていないのに、
> class Aと書くだけで、なぜAというクラスの情報がA.hの中にあるということを認識してくれるのでしょうか?
> なんか未定義エラーになってもおかしくないような気がするのですが。
> コンパイラが勝手に探してくれると思っとけばいいですかね?

違います。
認識もしませんし、探索もしません。

たかぎさんが
「class A; のような不完全宣言を行った場合、Aのポインタや参照であれば使うことができます。
しかし、メンバを参照することも、A型のオブジェクトを生成または解体することもできません。」

と書かれていますが、これが「何故できるのか」、「何故できないのか」を
よ~く考えてください。
出来ないことはクラスの定義に関する情報(ヘッダファイルに記述されている情報)がないから
できないのです。
画像

シエル

Re:C++についての質問

#18

投稿記事 by シエル » 15年前

よ~~~~~~~~く考えました。なんとなく分かりました。ぽこさんありがとうございます。

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
}
/////////////////////////

Poco

Re:C++についての質問

#19

投稿記事 by Poco » 15年前

> class A;
> ↑つまりこう書くと「中身がないクラス」を作ったことになる。つまり不完全なクラス。
> でもクラス自体は作れてるから、そのクラスのポインタは使える。
> でも最終的には完全な状態のクラスAのメンバを呼び出して使用したいから、
> softyaさんが提示してくだった下記コードのようにA.hを取り込むことによって、
> クラスAのメンバが完全に定義されたことになり、クラスAのメンバを呼び出して
> 使用できるようになるというわけですね・・!
> 合ってますでしょうか?

合っています。
コンパイラの気持ちになれば、
「Aってのがクラス名ってのはわかるけどさぁ、Aのメンバがさっぱりわからないから、
 コンストラクタ呼出(生成)やメンバ関数呼び出しを行うコード書かれても、
 それが正しい記述か判断できないよ。」
ってことです。

----追記
ようやくプログラマになれた。
先は長いね。。 画像

シエル

Re:C++についての質問

#20

投稿記事 by シエル » 15年前

合ってましたか!良かったです!
かなり考えて理解できたので、忘れないと思います。
今回の質問は非常に勉強になりました。

ぽこさん、softyaさん、たかぎさん、暑い中どうもありがとうございました!
本当に助かりました!
これにて解決にさせていただきます!

Poco

Re:C++についての質問

#21

投稿記事 by Poco » 15年前

> ぽこさん、softyaさん、たかぎさん、暑い中どうもありがとうございました!

解決できて何よりです。
ホント暑いですよね。西日が差すから外より暑い。。。

閉鎖

“C言語何でも質問掲示板” へ戻る