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

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

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

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

Q&A

解決済

1回答

8327閲覧

外部シンボルは未解決・コンストラクタについて

KTMEI

総合スコア44

C++

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

0グッド

0クリップ

投稿2017/01/23 05:44

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

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

ソースをコンパイルすると以下2種類のエラーが出ます。

①error LINK2001: 外部シンボル""public: static class log4cpp::Category & Log::sub3"(?sub3@Log@@2AAVCategory@log4cpp@@A)"は未解決です。
②IntelliSense: "Log::Log()"(宣言された行8、ファイル名"プロジェクトフォルダ\Log.h"にアクセスできません。

①について
調べたところ、定義がない場合に発生するといったものを見つけることは
出来たのですが、Log.cppに定義しているのにも発生しているため、他にどのような
ことが考えられるか教えていただけないでしょうか。
尚、ここで実施したいことは、Logクラスで定義しているsub1,sub2,sub3のメンバに
取得したカテゴリのインスタンスを取得して保持したいのが目的です。

②について
Logクラスのコンストラクタがprivateになっているためpublicにするとメッセージ自体は
解消されますが、privateのままで他に解消する方法はありますでしょうか。

以下にソースを貼り付けますのでご教授頂けますでしょうか。

■ConsoleApplication4.cpp

C++

1#include "stdafx.h" 2#include "Log.h" 3 4int _tmain(int argc, _TCHAR* argv[]) 5{ 6 std::string initFileName; 7 initFileName = "log4cpp.properties"; 8 9 Log* logInstance = new Log(); 10 11 log4cpp::Category& sub1 = logInstance->getErrorFatalLogger(); 12 log4cpp::Category& sub2 = logInstance->getInfoWarnLogger(); 13 log4cpp::Category& sub3 = logInstance->getDebugLogger(); 14 15 printer::logging(sub1 , true); 16 printer::logging(sub2 , true); 17 printer::logging(sub3 , true); 18 19 log4cpp::Category::shutdown(); 20 21 getchar(); 22 return 0; 23}

■Log.h

C++

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

■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 Log::sub3; 17} 18///INFOおよびWARNのログ出力に使用 19log4cpp::Category& Log::getInfoWarnLogger() 20{ 21 return Log::sub2; 22} 23///ERRORおよびFATALのログ出力に使用 24log4cpp::Category& Log::getErrorFatalLogger() 25{ 26 return Log::sub1; 27} 28//パフォーマンスのログ出力に使用 29log4cpp::Category& Log::getPerformanceLogger() 30{ 31 return Log::sub3; 32} 33}

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは。

Log* logInstance = new Log();

log4cpp::Category& sub1 = logInstance->getErrorFatalLogger(); log4cpp::Category& sub2 = logInstance->getInfoWarnLogger(); log4cpp::Category& sub3 = logInstance->getDebugLogger();

が使い方間違いです。
Logクラスのデフォルト・コントスラクタをprivateにするということは、それを外部から呼び出せなくなります。つまり、デフォルト・コンストラクタを使うようなインスンタス生成をLogクラス外ではできないと言う意味になります。
従って、new Log();はできません。
log4cpp::Category& sub1 = logInstance->getErrorFatalLogger();等は、静的メンバ関数ですからインスタンスは不要です。
従って、log4cpp::Category& sub1 = Log::getErrorFatalLogger();のように呼び出せば良いです。

①について

privateだから外部リンケージ無しになり、異なる.cppソースとのリンクができないのだろうと思います。
それ以前に_tmain()側で「privateなのでアクセスできない旨の」コンパイル・エラーにならないのが不思議ですが。

②について

インテリセンスはエラーでないものでもエラーとして報告してきます。なので私はガン無視してます。
無効にすることもできるようです。

投稿2017/01/23 06:01

Chironian

総合スコア23272

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

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

KTMEI

2017/01/23 06:27

ご回答ありがとうございます。 以下のように修正しましたが、やはり①のエラーがsub3,sub2,sub1に対して出力されて、 コンパイルエラーとなってしまいます。私の宣言の仕方がおかしいのでしょうか・・? ■ConsoleApplication4.cpp ```C++ int _tmain(int argc, _TCHAR* argv[]) { std::string initFileName; initFileName = "log4cpp.properties"; log4cpp::PropertyConfigurator::configure(initFileName); log4cpp::Category& root = log4cpp::Category::getRoot(); log4cpp::Category& sub1 = Log::getErrorFatalLogger(); log4cpp::Category& sub2 = Log::getInfoWarnLogger(); log4cpp::Category& sub3 = Log::getDebugLogger(); printer::logging(sub1, true); printer::logging(sub2, true); printer::logging(sub3, true); log4cpp::Category::shutdown(); getchar(); return 0; } ```
Chironian

2017/01/23 06:43

ああ、よく見るとsub1, sub2, sub3はLog::Log()関数内のローカル変数ですね。それではLog::Log()関数の外からアクセスできません。 下記のように修正すると良い筈です。 log4cpp::Category& Log::getDebugLogger() { return log4cpp::Category::getInstance(CATEGORY_DEBUG); } しかし、元の関数でコンパイル・エラーにならないのが謎です。リンクまで進まない筈なのですが。 本当にコンパイルしているソースそのものでしょうか? 質問のためにシュリンクし、コンパイルに通らなくなっているということはないでしょうか?
KTMEI

2017/01/23 08:11

ご回答ありがとうございます。 余計な部分はシュリンクしていますが質問している箇所とは別なので、 関連ないと思っています(知識不足により関連があったのかもしれないです・・)。 お伝えしたエラー以外は発生していませんでした。 今回ご回答頂いた内容を元に確認したところエラーなくコンパイルも通り、 ビルド出来ました。ありがとうございます。 今回の質問の経緯は以下でした。 sub1~sub3はLog.h内で以下のように定義(staticではない)していました。 log4cpp::Category& sub3; このsub3を他のクラスから取得するためにインスタンスを生成し、 インスタンスを生成する際にコンストラクタの中でCategoryの 取得を行えばいいと思い、先にお伝えしました実装を行っていました。 今回、コメント頂いた中にLog()関数内のローカル変数とご指摘がありましたが、 Log()内でsub3を再定義しているからローカル変数ということでしょうか。 インスタンスを生成する際に、CategoryをLogクラスのメンバsub1~sub3への 取得を行い、生成したインスタンスのsub1~sub3を取得したい場合、 どのような実装を行えばいいのでしょうか。
Chironian

2017/01/23 08:49

> 余計な部分はシュリンクしていますが質問している箇所とは別なので、 > 関連ないと思っています(知識不足により関連があったのかもしれないで> す・・)。 > お伝えしたエラー以外は発生していませんでした。 ここまで確認されていたのであれば完璧です。 私こそ間違った指摘してすいません。 > sub1~sub3はLog.h内で以下のように定義(staticではない)していました。 ごめんなさい。これを見落としてました。これがあればコンパイル・エラーにはならないです。 あああ、今になって気が付きました。 ↓staticなメンバ変数はヘッダに書いただけでは領域が確保されませんのでリンクエラーになります。 http://www7b.biglobe.ne.jp/~robe/cpphtml/html02/cpp02028.html なので、回答に記載した「privateだから外部リンケージ無しになり、異なる.cppソースとのリンクができないのだろうと思います。 」は間違いです。Log::sub3をLog::Log()と混同してしまっていたようです。 どうもミスが多くて申し訳ないです。 > Log()内でsub3を再定義しているからローカル変数ということでしょうか。 その通りです。
KTMEI

2017/01/24 02:55

ご丁寧に解説していただきありがとうございました! とてもわかり易かったです! 新たな質問がありましたが、質問の方向が異なってきたので 以下で質問を作成しました。 https://teratail.com/questions/63207?modal=q-comp もしよろしければ上記へのコメントもよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問