ページ 11

樽見

Posted: 2017年7月08日(土) 19:39
by ファイルをまたいで構造体は使えない!?
こんにちは。
今、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;」のところでエラーが起きないのでしょうか?

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

Re: 樽見

Posted: 2017年7月08日(土) 19:53
by みけCAT
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の実体の定義があるからです。

Re: 樽見

Posted: 2017年7月08日(土) 20:23
by 樽見
>>みけCATさん

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

Re: 樽見

Posted: 2017年7月09日(日) 05:35
by かずま
簡単な修正方法は、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: 樽見

Posted: 2017年7月09日(日) 14:03
by 樽見
>>かずま

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

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

Re: 樽見

Posted: 2017年7月09日(日) 16:36
by keito94
オフトピック
入れ替わり事故がまたw