我試圖實現具有3個級別的信息的記錄器:一般(日期/時間),上下文,消息C++圖案:1x基站類+ NX派生類但具有_Last resort_派生類
爲了達到這個目標我想implemnet以下模式:
- Logger類(非此相關)
- Context類
- 基類
LoggerContext
,這有根的功能erating一般水平的相關信息 - 派生類,添加上下文中的具體的相關信息(具體爲應用程序的一部分)
- 基類
有趣的部分開始,我嘗試有一個沒有上下文。也就是說,如果記錄器沒有上下文被調用,那麼應該使用單例LoggerContextNone
。
這裏我的代碼,不管我怎麼打開它,不編譯:
#include <string>
#include <iostream>
#include <stdexcept>
using namespace std;
enum class LoggerArea {
LOGGER_NONE, LOGGER_DOWNLOAD, LOGGER_COMPUTE,
};
class ELoggerContext: std::runtime_error {
using std::runtime_error::runtime_error;
};
class LoggerContextNone; // forward declaration, only needed for
// the commented version of the code
class LoggerContext {
protected:
LoggerArea mLA;
public:
LoggerContext(LoggerArea la);
virtual ~LoggerContext() = 0;
/*
static LoggerContext& getEmptyContext() {
static LoggerContextNone loggerContextNone = { LoggerArea::LOGGER_NONE };
return loggerContextNone;
}
*/
std::string getGeneral();
virtual std::string getContext() = 0; // pure virtual
};
string LoggerContext::getGeneral() {
return "general informations";
}
LoggerContext::LoggerContext(LoggerArea la) :
mLA(la) {
if (la == LoggerArea::LOGGER_NONE) {
throw ELoggerContext("LOGGER_NONE cannot be instantiated");
}
}
class LoggerContextNone : LoggerContext {
private:
LoggerContextNone() {
mLA = LoggerArea::LOGGER_NONE;
}
public:
virtual ~LoggerContextNone() override {
}
virtual std::string getContext() override {
return " ";
}
static LoggerContextNone& getInstance() {
static LoggerContextNone instance {};
return instance;
}
};
int main() {
// this should not be compilable:
LoggerContextNone n{LoggerArea::LOGGER_NONE};
// this should at least throw an error at run time:
LoggerContext n{LoggerArea::LOGGER_NONE};
return 0;
}
目標:
LoggerContextNone
應該LoggerContext
派生,因爲我們需要getGeneral()
LoggerContextNone
應不可實例化getInstance(單例)- 基類肩d有沒有空的構造函數,但派生類應該有一個
LoggerContextNone
不應該調用超構造函數,否則會拋出一個錯誤ELoggerContext
- 從
LoggerContext
任何派生類不應該能夠覆蓋getGeneral()
實際上是否可以在C++中實現這一點?我正在尋找一個乾淨的解決方案(沒有工廠,...)
編譯器的錯誤是:
19_virtual_class.cpp: In constructor ‘LoggerContextNone::LoggerContextNone()’:
19_virtual_class.cpp:45:22: error: no matching function for call to ‘LoggerContext::LoggerContext()’
LoggerContextNone() {
^
[...]
19_virtual_class.cpp: In function ‘int main()’:
19_virtual_class.cpp:62:46: error: no matching function for call to ‘LoggerContextNone::LoggerContextNone(<brace-enclosed initializer list>)’
LoggerContextNone n{LoggerArea::LOGGER_NONE};
^
最後說明一點:這個模式似乎我的概念是很簡單:從一個基類派生許多類的另外還有一個默認類。
編輯:
如果我調整代碼由@Angew:
#include <string>
#include <iostream>
#include <stdexcept>
using namespace std;
enum class LoggerArea {
LOGGER_NONE, LOGGER_DOWNLOAD, LOGGER_COMPUTE,
};
class ELoggerContext: std::runtime_error {
using std::runtime_error::runtime_error;
};
class LoggerContextNone;
class LoggerContext {
protected:
LoggerArea mLA;
class LoggerContextNone_AccessToken
{
friend LoggerContextNone;
LoggerContextNone_AccessToken() {}
};
explicit LoggerContext(LoggerContextNone_AccessToken) : mLA(LoggerArea::LOGGER_NONE) {}
public:
LoggerContext(LoggerArea la);
virtual ~LoggerContext() = 0;
std::string getGeneral();
virtual std::string getContext() = 0;
};
string LoggerContext::getGeneral() {
string s = "general informations:";
if (mLA==LoggerArea::LOGGER_NONE) { s += "LOGGER_NONE"; }
else if (mLA==LoggerArea::LOGGER_DOWNLOAD) { s += "LOGGER_DOWNLOAD"; }
else if (mLA==LoggerArea::LOGGER_COMPUTE) { s += "LOGGER_COMPUTE"; }
else { s += "??????????"; }
return s;
}
LoggerContext::LoggerContext(LoggerArea la) :
mLA(la) {
if (la == LoggerArea::LOGGER_NONE) {
throw ELoggerContext("LOGGER_NONE cannot be instantiated");
}
}
class LoggerContextNone : LoggerContext {
private:
LoggerContextNone(): LoggerContext(LoggerContextNone_AccessToken()) {}
public:
virtual ~LoggerContextNone() override {
}
virtual std::string getContext() override {
return " ";
}
static LoggerContextNone& getInstance() {
static LoggerContextNone instance {};
return instance;
}
};
class LoggerContextDerived : LoggerContext {
public:
virtual std::string getContext() override {
return "derived context";
}
};
int main() {
LoggerContextDerived n {LoggerArea::LOGGER_DOWNLOAD};
// cout << "General : " << n.getGeneral() << endl;
// cout << "Context : " << n.getContext() << endl;
return 0;
}
我不能實例派生類。 g++
說:
9_virtual_class.cpp: In function ‘int main()’:
19_virtual_class.cpp:78:54: error: no matching function for call to ‘LoggerContextDerived::LoggerContextDerived(<brace-enclosed initializer list>)’
LoggerContextDerived n {LoggerArea::LOGGER_DOWNLOAD};
^
而且它建議我使用複製構造函數或移動構造函數。 對我意味着什麼,構造
LoggerContext(LoggerArea la);
是不是在派生類中可見。
感謝您長期以來的答覆,但它接縫要有些東西仍然不適用於構造函數,請參閱我對該問題的編輯。 – LiPo
@LiPo這是一個相互無關的問題。您不能使用基類ctor構造C++中的派生類。如果你想在派生類中使用單參數,你需要在那裏定義這樣的一個ctor。或者使用構造函數繼承('使用LoggerContext :: LoggerContext'),但那會繼承*所有*構造函數。 – Angew
@LiPo您可能想了解更多關於C++構造函數如何在[好書](http://stackoverflow.com/q/388242/1782465)中工作的內容。 – Angew