質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

5300閲覧

インクルードガードをつけてもヘッダーとソースファイルとで分けないと複数定義されているというエラーがでるのか?

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/09/10 02:01

編集2020/09/10 02:01

提示画像のような既に存在しますのエラーが出ていますがこれはインクルードガードをつけてもエラーになるのでしょうか?やっぱりc++ではソースとヘッダーで分けるべきでinlineなどつけて対処すべきなのでしょうか?

イメージ説明

#ifndef VECTOR_HPP #define VECTOR_HPP #include "stdio.h" #include "math.h" class Vector3 { public: float x; float y; float z; public: Vector3(float xx = 0, float yy = 0, float zz = 0) { x = xx; y = yy; z = zz; } //掛け算 Vector3 operator* (Vector3 pos) { this->x = pos.x * this->x; this->y = pos.y * this->y; this->z = pos.z * this->z; return *this; } //掛け算 Vector3 operator- (Vector3 pos) { this->x = this->x - pos.x; this->y = this->y - pos.y; this->z = this->z - pos.z; return *this; } static Vector3 Cross(Vector3 a, Vector3 b) { Vector3 temp; temp.x = a.y * b.z - a.z * b.y; temp.y = a.z * b.x - a.x * b.z; temp.z = a.x * b.y - a.y * b.x; return temp; } static float Dot(Vector3 a, Vector3 b) { float t = (a.x * a.x) + (a.y * a.y); return t; } }; class Matrix4 { public: float x; float y; float z; float w; //コンストラクタ Matrix4() { x = 0.0; y = 0.0; z = 0.0; w = 0.0; } Matrix4(Vector3 p) { x = p.x; y = p.y; z = p.z; w = 1.0f; } Matrix4(float xx, float yy, float zz, float ww) { x = xx; y = yy; z = zz; w = ww; } Matrix4(float xx, float yy, float zz) { x = xx; y = yy; z = zz; w = 1.0f; } //一列と行列を掛け算 Matrix4 operator * (const Matrix4& M)const { Matrix4 t; t.x = (x * 1) + (y * 0) + (z * 0) + (w * M.x); t.y = (x * 0) + (y * 1) + (z * 0) + (w * M.y); t.z = (x * 0) + (y * 0) + (z * 1) + (w * M.z); t.w = (x * 0) + (y * 0) + (z * 0) + (w * M.w); return t; } }; class Matrix3 { public: float x; float y; float z; //コンストラクタ Matrix3() { x = 0.0; y = 0.0; z = 0.0; } Matrix3(Vector3 p) { this->x = p.x; this->y = p.y; this->z = p.z; } Matrix3(float x = 0, float y = 0, float z = 0) { this->x = x; this->y = y; this->z = z; } }; //ベクトルの大きさを出す //float Vector_scalar(Vector3 p); float Vector_scalar(Vector3 p) { float r = (p.x * p.x) + (p.y * p.y) + (p.z * p.z); return r; } //スケール変換 //void Scale_change(float Sx, float Sy, float Sz, float pos_x, float pos_y, float pos_z); void Scale_change(float Sx, float Sy, float Sz, float pos_x, float pos_y, float pos_z) { //Scale行列 float ScaleMatrix4[4][4] = { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,1}, }; //行列に大きさを設定 ScaleMatrix4[0][0] = Sx; ScaleMatrix4[1][1] = Sy; ScaleMatrix4[2][2] = Sz; //座標を行列に設定 float Vector3[4]; Vector3[0] = pos_x; Vector3[1] = pos_y; Vector3[2] = pos_z; Vector3[3] = 1; float t = 0; t = (Vector3[0] * ScaleMatrix4[0][0]) + (Vector3[1] * ScaleMatrix4[0][1]) + (Vector3[2] * ScaleMatrix4[0][2]) + (Vector3[3] * ScaleMatrix4[0][3]); printf("%f\n", t); t = (Vector3[0] * ScaleMatrix4[1][0]) + (Vector3[1] * ScaleMatrix4[1][1]) + (Vector3[2] * ScaleMatrix4[1][2]) + (Vector3[3] * ScaleMatrix4[1][3]); printf("%f\n", t); t = (Vector3[0] * ScaleMatrix4[2][0]) + (Vector3[1] * ScaleMatrix4[2][1]) + (Vector3[2] * ScaleMatrix4[2][2]) + (Vector3[3] * ScaleMatrix4[2][3]); printf("%f\n", t); t = (Vector3[0] * ScaleMatrix4[3][0]) + (Vector3[1] * ScaleMatrix4[3][1]) + (Vector3[2] * ScaleMatrix4[3][2]) + (Vector3[3] * ScaleMatrix4[3][3]); printf("%f\n", t); }; //三次元回転変換 class Quaternion { public: float x; float y; float z; float w; public: Quaternion(float xx = 0, float yy = 0, float zz = 0, float ww = 0) { x = xx; y = yy; z = zz; w = ww; } //今の方向 , 向きたい方向 void process(Vector3 s, Vector3 p) { // Vector3 s(1, 1, 0);//今の方向 // Vector3 p(-1, 1, 0);//新しい方向ベクトル Vector3 newFacing;//新しい座標に向かうベクトルを計算して正規化 Vector3 t = p - s; float len = (float)sqrt(Vector_scalar(t)); newFacing.x = t.x / len; newFacing.y = t.y / len; newFacing.z = t.z / len; // printf("方向ベクトル x: %f\n", newFacing.x); // printf("方向ベクトル y: %f\n", newFacing.y); // printf("方向ベクトル z: %f\n\n", newFacing.z); Vector3 pa = Vector3::Cross(Vector3(0, 0, 1), newFacing); float sp = (float)sqrt(Vector_scalar(pa)); Vector3 a;//回転軸 a.x = pa.x / sp; a.y = pa.y / sp; a.z = pa.z / sp; float r = (float)acos(Vector3::Dot(Vector3(0, 0, 1), newFacing)); // printf("回転軸 x: %f\n", a.x); // printf("回転軸 y: %f\n", a.y); // printf("回転軸 z: %f\n\n", a.z); // printf("回転角 θ: %f\n", r); Quaternion q; q.w = (float)cos(r / 2); q.x = (float)newFacing.x * (float)cos(r / 2); q.y = (float)newFacing.y * (float)sin(r / 2); q.z = (float)newFacing.z * (float)sin(r / 2); ////////////////////////////////////////////////////////// printf("q w: %f\n", q.w); printf("q x: %f\n", q.x); printf("q y: %f\n", q.y); printf("q z: %f\n", q.z); ///////////////////////////////////////////////////////// } }; void t() { //ワールド座標 Matrix3 now[6] = { Matrix3(-160, +100, 1), Matrix3(-160, -100, 1), Matrix3(+160, -100, 1), /////////////////////////////////// Matrix3(-160, +100, 1), Matrix3(+160, +100, 1), Matrix3(+160, -100, 1) }; //ビュー行列 const Matrix3 s[3] = { Matrix3((2.0f / 640.0f),0.0f,0.0f), Matrix3(0.0f,(2.0f / 400.0f),0.0f), Matrix3(0.0f,0.0f,1.0f), }; Vector3 p(0, 0, 0); for (int i = 0; i < 6; i++) { p.x = (now[i].x * s[0].x) + (now[i].y * s[0].y) + (now[i].z * s[0].z); p.y = (now[i].x * s[1].x) + (now[i].y * s[1].y) + (now[i].z * s[1].z); p.z = (now[i].x * s[2].x) + (now[i].y * s[2].y) + (now[i].z * s[2].z); printf("頂点:%d\n", i + 1); printf("p.x: %.2f\n", p.x); printf("p.y: %.2f\n", p.y); printf("p.z: %.2f\n\n\n", p.z); } //int _C = getchar(); // return 0; } #endif

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

その提示コードがヘッダファイルで,
それを複数の場所からincludeしているということでしょうか.

例えば,
あるヘッダの中にvoid f(){ ... }という実装が書かれていて,
それを,A.cppとB.cppとからincludeしたならば,それは,

//A.cpp void f(){ ... } //B.cpp void f(){ ... }

と書いたことと一緒なわけです.
なので,リンカが「f()の定義が2つあるぞクソが」って吠える.

「インクルードガード」という言葉だけを覚えて,その意味を把握していないのではありませんか?
なんとなく#ifndef どうのこうのとか書く前に,一度,きちんと

  • 一体何を「ガード」するための記述なのか?
  • あるいは「includeって何?」というところ

を把握しましょう.
でないと,毎回同じ目にあいますよ,きっと.


(includeに関しては,一度はこんなくだらないことをやって遊ぶべき)

//cpp #include <stdio.h> int #include "Header1.h" #include "Header2.h" "Hello world" ); return 0; }
//Header1.h main(
//Header2.h ) { printf(

投稿2020/09/10 02:22

編集2020/09/10 02:43
fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

インクルード・ガードは コンパイル時に定義/宣言の重複を抑止するものであり、
リンク時には効果ありません。※ 件のエラーはリンク時のエラーです。

inline 指定するか、さもなくば ヘッダ内では宣言のみとし定義は~.cppに置くことになります。

※ さもないと ODR(One Definition Rule):「"定義はただひとつ"の原則」に反する(のでエラー)

投稿2020/09/10 02:50

編集2020/09/10 03:11
episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

ヘッダファイルで関数を定義するときは、inlineとする必要があります(inline関数は、複数生成しても自動でマージしてくれるので、今回のような問題にはなりません)。

class{}の内側で定義したメソッドは、自動的にinlineとみなされます。

投稿2020/09/10 02:22

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/09/10 02:23

> やっぱりc++ではソースとヘッダーで分けるべきでinlineなどつけて対処すべきなのでしょうか? グローバル変数を含まない場合、「ソースとヘッダーで分ける」あるいは「inlineを付ける」のどちらかで対応できます。
episteme

2020/09/10 03:27 編集

「マージされる」には疑問。 inline int f() { return 1; } inline int f() { return 2; } こんなとき、どうマージすんの? ってなるし。 コンパイル単位ごとに別物として扱われる ではなかろか。
maisumakun

2020/09/11 01:34 編集

> コンパイル単位ごとに別物として扱われる ではなかろか。 inline関数でも、staticとしなければ外部リンケージです。 同じinline関数が複数の翻訳単位で定義された場合、全く同じ定義であれば実体が1つ以下になることが保証されていますが、ご提示のような「同シグネチャで異なる定義のinline関数が複数ある」ような状況はリンクエラーとなります。 http://lpha-z.hatenablog.com/entry/2019/02/17/231500
guest

0

質問文に書かれている通り、
普通は、ヘッダファイルにはclass定義などの宣言のみを書き、関数定義はソースファイル側に書きます。
(ヘッダ側にinlineで置くことも一応は出来ます。実際class宣言内で定義している関数はinline扱いになっています)

提示された書き方だと、ヘッダファイル(.hpp)をインクルードしたソース(.cpp)の全てに同名の関数定義が含まれてしまうことになります。
リンクの時に全ソースファイルを突き合わせる際に、同じ関数が複数存在することになるのでエラーとなります。

投稿2020/09/10 02:20

編集2020/09/10 02:32
hidezzz

総合スコア1248

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問