🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

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

Visual Studio 2013

Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

Q&A

解決済

2回答

29603閲覧

リンクエラー:既に定義されている

KTMEI

総合スコア44

C++

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

Visual Studio 2013

Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

0グッド

0クリップ

投稿2017/01/24 02:53

C++初心者です。
ほぼ触ったことがないので、細かい部分も教えていただきたいです。

C++を使用して試しにログを出力するプログラムを作成しています。

以下のクラスでリンクエラーが出てしまいます。
静的なメンバーを初期化し、初期化したメンバーを
cppファイル側で使用するように実装していますが、
Log.objですでに定義されていると言われてしまいます。

エラー 5 error LNK2005: "public: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const Log::CATEGORY_ERROR" (?CATEGORY_ERROR@Log@@2V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@B) は既に Log.obj で定義されています。 プロジェクト.obj プロジェクト

実現したいこととしてはconst static のstring型の固定文字(sub1)を
変数で保持しておき、保持している値をLog.cppに書いている
メソッドで使用したいです。

const static std::string CATEGORY_ERROR = "sub1";
(CATEGORY_ERRORをLog.cpp内のメソッドで使用したい。)

①なぜ本リンクエラーが出るのでしょうか。
②どのような実装にすれば上記を実現出来るでしょうか。

現在の実装コードを以下に記載します。
■Log.h

C++

1#pragma once 2#include<log4cpp/Category.hh> 3#include<log4cpp/PropertyConfigurator.hh> 4 5class Log 6{ 7private: 8 9public: 10 Log(); 11 ~Log(); 12 ///ログ出力に関する設定ファイルのファイル名 13 const static std::string PROPATIES_FILE_NAME;// = "log4cpp.properties"; 14 const static std::string CATEGORY_ERROR;//= "sub1"; 15 const static std::string CATEGORY_INFO;// = "sub1.sub2"; 16 const static std::string CATEGORY_DEBUG;// = "sub1.sub2.sub3"; 17 18 log4cpp::Category& root = getErrorFatalLogger();//仮 19 log4cpp::Category& sub1 = getErrorFatalLogger(); 20 log4cpp::Category& sub3 = getInfoWarnLogger(); 21 log4cpp::Category& sub2 = getDebugLogger(); 22 23 static log4cpp::Category& getErrorFatalLogger(); 24 static log4cpp::Category& getInfoWarnLogger(); 25 static log4cpp::Category& getDebugLogger(); 26 static log4cpp::Category& getPerformanceLogger(); 27 28}; 29// 30const std::string Log::PROPATIES_FILE_NAME = "log4cpp.properties"; 31const std::string Log::CATEGORY_ERROR = "sub1"; 32const std::string Log::CATEGORY_INFO = "sub1.sub2"; 33const std::string Log::CATEGORY_DEBUG = "sub1.sub2.sub3";

■Log.cpp

C++

1#include "stdafx.h" 2#include "Log.h" 3Log::Log() 4{ 5 log4cpp::PropertyConfigurator::configure(PROPATIES_FILE_NAME); 6 log4cpp::Category& sub3 = log4cpp::Category::getInstance(CATEGORY_DEBUG); 7 log4cpp::Category& sub2 = log4cpp::Category::getInstance(CATEGORY_INFO); 8 log4cpp::Category& sub1 = log4cpp::Category::getInstance(CATEGORY_ERROR); 9} 10Log::~Log() 11{ 12} 13///DDEBUGのログ出力に使用 14log4cpp::Category& Log::getDebugLogger() 15{ 16 return log4cpp::Category::getInstance(CATEGORY_DEBUG); 17} 18///INFOおよびWARNのログ出力に使用 19log4cpp::Category& Log::getInfoWarnLogger() 20{ 21 return log4cpp::Category::getInstance(CATEGORY_INFO); 22} 23///ERRORおよびFATALのログ出力に使用 24log4cpp::Category& Log::getErrorFatalLogger() 25{ 26 return log4cpp::Category::getInstance(CATEGORY_ERROR); 27} 28//パフォーマンスのログ出力に使用 29log4cpp::Category& Log::getPerformanceLogger() 30{ 31 return log4cpp::Category::getInstance(CATEGORY_DEBUG); 32}

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

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

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

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

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

guest

回答2

0

ベストアンサー

C++

1const std::string Log::PROPATIES_FILE_NAME = "log4cpp.properties"; 2const std::string Log::CATEGORY_ERROR = "sub1"; 3const std::string Log::CATEGORY_INFO = "sub1.sub2"; 4const std::string Log::CATEGORY_DEBUG = "sub1.sub2.sub3";

これを、cpp ファイルの方に書いてください。

ファイルを複数のcppにインクルードしているため、これらのオブジェクトがすでに定義されている事になります。

pragma once して、インクルードガードしていても、分割コンパイル時にこれらが作成されるため、名前が衝突しリンカエラーになります。

投稿2017/01/24 03:04

MasashiKimura

総合スコア1150

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

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

KTMEI

2017/02/15 00:32

cppファイルに記載することで問題なく動作しました! ありがとうございました!
guest

0

こんにちは。

よくやってしまうミスです。
ヘッダで実体を定義した場合、複数の.cppからそのヘッダをインクルードすると、それぞれの.cppでその実体が定義されてしまいます。そのため、多重定義エラーになります。

対策はいつくか有りますが、基本は外部リンケージをなくすことです。
そのためには、各const宣言にstaticも追加する、無名名前空間に入れるのどちらかでOKです。

C++

1static const std::string Log::PROPATIES_FILE_NAME = "log4cpp.properties"; 2static const std::string Log::CATEGORY_ERROR = "sub1"; 3static const std::string Log::CATEGORY_INFO = "sub1.sub2"; 4static const std::string Log::CATEGORY_DEBUG = "sub1.sub2.sub3";

もしくは、下記です。

C++

1namespace 2{ 3const std::string Log::PROPATIES_FILE_NAME = "log4cpp.properties"; 4const std::string Log::CATEGORY_ERROR = "sub1"; 5const std::string Log::CATEGORY_INFO = "sub1.sub2"; 6const std::string Log::CATEGORY_DEBUG = "sub1.sub2.sub3"; 7}

投稿2017/01/24 03:01

Chironian

総合スコア23272

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

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

KTMEI

2017/01/24 04:41

ご回答ありがとうございます。 static const std::string Log::PROPATIES_FILE_NAME = "log4cpp.properties"; static const std::string Log::CATEGORY_ERROR = "sub1"; static const std::string Log::CATEGORY_INFO = "sub1.sub2"; static const std::string Log::CATEGORY_DEBUG = "sub1.sub2.sub3"; の場合、「ストレージクラスの指定子が識別子に対して誤って指定されています。」 となります。 また、無名名前空間に入れた場合、 「シンボルは名前空間 'anonymous-namespace' 内で定義出来ません。」 となってしまいます。 cppファイルの方に直接書かなければ行けないものなのでしょうか・・?
Chironian

2017/01/24 05:05

ああ、すいません。Logクラス内のstatic定義でした。 ということは、外部リンケージを無しにするのは、Logクラス内で外部リンケージ有りと定義していることと矛盾します。なので、cppファイルで定義するしかなかったと思います。 つまり、MasashiKimuraさんの回答が正解です。すいません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問