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

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

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

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

Q&A

解決済

3回答

11255閲覧

fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。の直し方

taro9292

総合スコア26

C++

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

0グッド

0クリップ

投稿2021/06/09 01:53

ランダムに値を返す関数をrandam.hで定義し、
それをNormalMode.hとNormalMode.cppで呼び出しているのですが、
エラーがでてしまいました。おそらく#includeで問題が起きていると考えていますが、
仕組みが理解できず、どう直せばいいかわかりません。
以下は4つのファイルで構成されております。

環境はvisualStudio2019です。

エラー内容
1>: error LNK2005: "int __cdecl Randam10(void)" (?Randam10@@YAHXZ) は既に NormalMode.obj で定義されています。
1>: fatal error LNK1169: 1 つ以上の複数回定義されているシンボルが見つかりました。

#ifndef func_H #define func_H #include <random> //func.h int Randam10() { std::random_device rnd; // 非決定的な乱数生成器を生成 std::mt19937 mt(rnd()); // メルセンヌ・ツイスタの32ビット版、引数は初期シード値 std::uniform_int_distribution<> randam(1, 10); // [1,10] 範囲の一様乱数 return randam(mt); }
//NormalMode.h #ifndef NormalMode_H #define NormalMode_H #include <string> #include "func.h"
//NormalMode.cpp #include <iostream> #include "NormalMode.h" #include <ctype.h> #include <random> #include <string>
//main.cpp #include <iostream> #include "NormalMode.h"

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

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

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

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

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

guest

回答3

0

ベストアンサー

仕組みが理解できず、

main.cpp と NormalMode.cpp が,NormalMode.hをincludeしている.
(なので,コンパイル前に,両cppの #include "NormalMode.h" の部分が NormalMode.h の内容に置き換わる)

で,NormalMode.hは #include "func.h" が書かれているから,ここがまた func.h の内容に置き換わる.
func.h には関数Randam10()の定義が書かれているのだから,

全てのincludeの置き換えが済んだとき,こんな感じになる.

//(main.cppのコンパイル前の状態) ... int Randam10() { ... } //関数Randam10の定義 ...
//(NormalMode.cppのコンパイル前の状態) ... int Randam10() { ... } //関数Randam10の定義 ...

2つの翻訳単位に,Randam10()の定義が存在する状態.
だから,リンク時に多重定義になっちゃう.


一般に(と言っていいか?),includeされる側のファイル(ヘッダ)に関数の定義(のような,定義が複数になったらまずい物)を書かないのでは,このような問題を回避するため.

解決方法はいくつかある.

  • (普通のやりかた:)func.h には 関数Randam10 の宣言を書き,定義は別の翻訳単位(例えばfunc.cppとか)に書く
  • (関数次第では悪くはないやり方:)inline int Randam10(){ ... }とする
  • (とりあえず回避されるが普通じゃないやり方:)static int Randam10(){ ... } とか namespace{ int Randam10(){ ... } } とかする

投稿2021/06/09 02:51

編集2021/06/09 03:05
fana

総合スコア11708

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

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

fana

2021/06/09 03:07

(なんか最近,回答投稿すると,末尾辺りが編集中の古い内容? になるなぁ.編集しようとするとちゃんとした内容が存在しているんだけど)
maisumakun

2021/06/09 06:56

自分の場合は、「投稿したら404ページ」が多発しています。
fana

2021/06/09 07:00

言われてみれば,404とか,ずっと投稿処理中の表示のままになっちゃうとかもありますね.
taro9292

2021/06/09 07:05

ありがとうございます。関数だけでもヘッダファイルとして宣言?し、cppで定義?することでエラーがなくなりました。 C、C++で難しく感じるのはこのincludeの流れだと感じます。 ヘッダーファイルが複数あるとよくわからなくなりますね。 やっぱり慣れが必要でしょうか
fana

2021/06/09 07:08

・ヘッダファイルは何のために用意しているのか? ・includeとは何か? という点を押さえればよいでしょう. (ここを把握せずになんとなく雰囲気でincludeを書いてるのではダメ)
guest

0

エラーに出ている日本語のとおりで、
関数定義が複数箇所にある、というエラーです

それを一つにしよう、ってはなしになりますが。

投稿2021/06/09 02:09

y_waiwai

総合スコア87800

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

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

taro9292

2021/06/09 02:33

一つにしようってどういう意味ですか?
y_waiwai

2021/06/09 02:40

同じ関数の定義がいくつもあるからエラーになってるんです。 それを一つにしないとダメだ、ってことですが
guest

0

そもそも関数の実装をヘッダに書くのがよろしくないと思いますが、
NormalMode.h の多重 include ガードがうまく効くのですかねこれ。

C++

1#ifndef NormalMode_H 2#define NormalMode_H 34// 最後に #endif がないと期待する動作にはならない可能性がありますが大丈夫?

投稿2021/06/09 02:00

tacsheaven

総合スコア13703

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

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

taro9292

2021/06/09 02:10

#endif はあります。 ヘッダーではなく、cppファイルに関数を実装したほうが良いということでしょうか?
tacsheaven

2021/06/09 02:12

そうです。ヘッダは「定義」を公開するために使用するものなので、実体は cpp 内に書くのが普通です。
taro9292

2021/06/09 02:29

cppに直したんですけど、同じエラーですね
maisumakun

2021/06/09 02:33

> cppに直したんですけど、同じエラーですね どのように直したのですか?(拡張子だけ変えても、「それを#includeで呼び出す」という状況が変わらなければ何も変化しません)
tacsheaven

2021/06/09 02:55

「定義」と「宣言」の違いを理解できていないと思う……
taro9292

2021/06/09 06:39

定義と宣言の違いは考えたことがないです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問