樽見

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ファイルをまたいで構造体は使えない!?

樽見

#1

投稿記事 by ファイルをまたいで構造体は使えない!? » 2年前

こんにちは。
今、C++でシュミレーションゲームを作っているのですが、その中で「ファイルをまたいで構造体が使えない」という症状が起きました。
関係するヘッダーファイル2つだけをシンプルに書き換えてみると、全く同じエラーが発生しましたので、投稿させていただきます。

Header.h

コード:

#pragma once 

class Header;
typedef struct A_ A;
typedef struct B_ B;

#include <iostream>
#include "Header1.h"

typedef struct A_{
	int t;
	double c;
}A;

typedef struct B_{
	short d;
	long w;
}B;

class Header{
public:
	void Draw(){ std::cout << "クラスHeaderが作られました" << std::endl; }
private:
	A a;
	B b;
	C c;
	D d;

	A myfunc(){
		A t = {2, 3.9};
		std::cout << "A型のtを初期化" << std::endl;
	}
};

Header1.h

コード:

#pragma once 

class Header1;
typedef struct C_ C;
typedef struct D_ D;

#include <iostream>
#include "Header.h"

typedef struct C_{
	int t;
	double c;
}C;

typedef struct D_{
	short d;
	long w;
}D;

class Header1{
public:
	void Draw(){ std::cout << "クラスHeader1が作られました" << std::endl; }
private:
	A a;	//エラー番号1
	B b;	//エラー番号2
	C c;
	D d;

	A myfunc(){  //エラー番号3
		A t = { 2, 3.9 };  //エラー番号4と5
		std::cout << "A型のtを初期化" << std::endl;
	}
};
※エラーの箇所は5つあり、すべてHeader1.hです。該当箇所にコメントをつけておきました。

エラー 1 error C2079: 'Header1::a' が 未定義の struct 'A_' で使用しています。
エラー 2 error C2079: 'Header1::b' が 未定義の struct 'B_' で使用しています。
エラー 3 error C2027: 認識できない型 'A_' が使われています。
エラー 4 error C2079: 't' が 未定義の struct 'A_' で使用しています。
エラー 5 error C2440: '初期化中' : 'initializer-list' から 'int' に変換できません。


どうしてもこのクラスで他のヘッダー宣言の構造体を使いたいのですが、どうすれば実現できるでしょうか?
また、どうしてHeader.hだと、「C c;」と「D d;」のところでエラーが起きないのでしょうか?

ご解答よろしくお願いいたします。

アバター
みけCAT
記事: 6252
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 樽見

#2

投稿記事 by みけCAT » 2年前

Header.hのincludeを展開すると

コード:

#pragma once 

class Header;
typedef struct A_ A;
typedef struct B_ B;

#include <iostream>
#pragma once 

class Header1;
typedef struct C_ C;
typedef struct D_ D;

#include <iostream>
// include "Header.h" (pragma onceにより無効)

typedef struct C_{
	int t;
	double c;
}C;

typedef struct D_{
	short d;
	long w;
}D;

class Header1{
public:
	void Draw(){ std::cout << "クラスHeader1が作られました" << std::endl; }
private:
	A a;	//エラー番号1
	B b;	//エラー番号2
	C c;
	D d;

	A myfunc(){  //エラー番号3
		A t = { 2, 3.9 };  //エラー番号4と5
		std::cout << "A型のtを初期化" << std::endl;
	}
};


typedef struct A_{
	int t;
	double c;
}A;

typedef struct B_{
	short d;
	long w;
}B;

class Header{
public:
	void Draw(){ std::cout << "クラスHeaderが作られました" << std::endl; }
private:
	A a;
	B b;
	C c;
	D d;

	A myfunc(){
		A t = {2, 3.9};
		std::cout << "A型のtを初期化" << std::endl;
	}
};
となります。
これを見ると、class Header1の宣言の前でAやBの実体が定義されていないのに、(ポインタや参照ではなく)AやBのサイズを必要とする定義をしようとしているので、エラーになることがわかります。
ファイルをまたいで構造体は使えない!? さんが書きました: どうしてもこのクラスで他のヘッダー宣言の構造体を使いたいのですが、どうすれば実現できるでしょうか?
この場合、struct A_、struct B_、struct C_、struct D_が互いに依存していないので、A_~D_の前方宣言がある位置に直接A_~D_の定義を書くのがいいでしょう。
ファイルをまたいで構造体は使えない!? さんが書きました: また、どうしてHeader.hだと、「C c;」と「D d;」のところでエラーが起きないのでしょうか?
「C c;」や「D d;」の前にCやDの実体の定義があるからです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

樽見

Re: 樽見

#3

投稿記事 by 樽見 » 2年前

>>みけCATさん

なるほど。確かに展開してみると、構造体が未定義なのがわかりますね。
ところで、これを前方宣言の直後に書くという事は、
typedef struct A_ A;
typedef struct B_ B;
の後に、インクルードを入れないで定義もするということでしょうか?

かずま

Re: 樽見

#4

投稿記事 by かずま » 2年前

簡単な修正方法は、Header.h も Header1.h も
8行目の #include ... を 19行目に移動する。

もっときれいな修正方法は、

Headere0.h

コード:

#pragma once 
 
struct A {
    int t;
    double c;
};
 
struct B {
    short d;
    long w;
};

struct C {
    int t;
    double c;
};
 
struct D {
    short d;
    long w;
};
Header.h

コード:

#pragma once 
 
#include <iostream>
#include "Header0.h"
 
class Header {
public:
    void Draw() { std::cout << "クラスHeaderが作られました" << std::endl; }
private:
    A a;
    B b;
    C c;
    D d;
 
    A myfunc() {
        A t = {2, 3.9};
        std::cout << "A型のtを初期化" << std::endl;
    }
};
Heaer1.h

コード:

#pragma once 
 
#include <iostream>
#include "Header0.h"
 
class Header1 {
public:
    void Draw() { std::cout << "クラスHeader1が作られました" << std::endl; }
private:
    A a;    //エラー番号1
    B b;    //エラー番号2
    C c;
    D d;
 
    A myfunc() {    //エラー番号3
        A t = { 2, 3.9 };    //エラー番号4と5
        std::cout << "A型のtを初期化" << std::endl;
    }
};

樽見

Re: 樽見

#5

投稿記事 by 樽見 » 2年前

>>かずま

解答ありがとうございます。

私も、まとめて同じヘッダーに宣言を書こうとは思ったのですが、構造体の中に別の構造体を使いたかったり、ぐちゃぐちゃになったような感じがしたので分けることにしました。
同じ定義分けはしない方がいいのでしょうか?

アバター
keito94
記事: 264
登録日時: 3年前
連絡を取る:

Re: 樽見

#6

投稿記事 by keito94 » 2年前

オフトピック
入れ替わり事故がまたw
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

返信

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