C++ C++;模式:1x基类+;Nx派生类,但具有_最后手段_派生类
我正在尝试实现一个具有3个级别信息的记录器:常规(日期/时间)、上下文和消息 为了实现这一目标,我尝试实现以下模式:C++ C++;模式:1x基类+;Nx派生类,但具有_最后手段_派生类,c++,c++11,design-patterns,C++,C++11,Design Patterns,我正在尝试实现一个具有3个级别信息的记录器:常规(日期/时间)、上下文和消息 为了实现这一目标,我尝试实现以下模式: 记录器类别(此处不相关) 上下文类 基类LoggerContext,具有生成一般级别信息的功能 派生类,它添加特定于上下文的信息(特定于应用程序的一部分) 有趣的部分是从我尝试无上下文开始的。也就是说,如果在没有上下文的情况下调用记录器,则应使用单例LoggerContextNone 在这里,我的代码,无论我如何转换,都不会编译: #include <string>
- 基类
,具有生成一般级别信息的功能LoggerContext
- 派生类,它添加特定于上下文的信息(特定于应用程序的一部分)
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;
}
最后一点注意:这个模式在概念上似乎很简单:许多类都是从一个基类派生的,另外还有一个默认类
编辑:
如果我通过@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;
}
它建议我使用复制构造函数或移动构造函数。
这对我来说意味着构造函数
LoggerContext(LoggerArea la);
在派生类中不可见。您可以实现所需的结果,但不完全是您尝试过的方式。有问题的要求是:
LoggerContextNone
不应调用超级构造函数,否则它将抛出错误ELoggerContext
派生类将始终调用基类的构造函数。在C++中,在没有运行构造函数的情况下,您不能合法地拥有类类型的有效对象。
但是,请注意,它将调用基的构造函数,这意味着它可以调用任意构造函数(派生类决定)。因此,您可以为基类提供一个专门供LoggerContextNone
使用的构造函数,如下所示:
class LoggerContext {
protected:
LoggerArea mLA;
LoggerContext() : mLA(LOGGER_NONE) {}
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
};
这将实现您想要的,但它将允许从LoggerContext
派生的所有类调用该默认构造函数,如果它们选择这样做的话。如果您想避免这种情况,并且只让该构造函数可用于LoggerContextNone
,则可以使用友谊技巧和标记分派来实现这一点:
class LoggerContext
{
protected:
class LoggerContextNone_AccessToken
{
friend LoggerContextNone;
LoggerContextNone_AccessToken() {}
};
explicit LoggerContext(LoggerContextNone_AccessToken) : mLA(LOGGER_NONE) {}
protected:
// ... the rest as before
};
LoggerContextNone::LoggerContextNone() : LoggerContext(LoggerContextNone_AccessToken())
{}
这意味着:
LoggerContext
的非抛出构造函数,需要传入LoggerContextNone\u AccessToken
对象LoggerContextNone\u AccessToken
有一个私有构造函数,这意味着只有它的朋友才能构造它LoggerContextNone
是LoggerContextNone\u AccessToken
的唯一朋友,因此它是唯一能够构造LoggerContextNone\u AccessToken
的类,也是唯一能够调用LoggerContext
的非抛出构造函数的类P>可选的,你可以考虑你是否真的需要< LoggerContextNone > >代码>。也许您可以让
LoggerContext
表现为LoggerContextNone
,只允许派生类提供非none行为。来自@Angew的答案对于模式的运行是至关重要的,但代码中还有许多(仍然存在一些)其他问题
这是我能做的最好的了,它仍然不起作用,但也许在接下来的几天里我100%得到了它:
#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() {};
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() {
// this was:
// static LoggerContextNone& getInstance() {
static LoggerContextNone instance {};
return &instance;
}
};
class LoggerContextDerived : public LoggerContext {
public:
LoggerContextDerived(LoggerArea la):LoggerContext(la) { };
virtual std::string getContext() override {
return "derived context";
}
virtual ~LoggerContextDerived() override {
}
};
int main() {
// test 1: derived class
LoggerContextDerived c1 {LoggerArea::LOGGER_DOWNLOAD}; // ok
cout << "General : " << c1.getGeneral() << endl; // ok
cout << "Context : " << c1.getContext() << endl; // ok
LoggerContext * c2 = &c1; // ok
// test 2: derived none class
LoggerContextNone * c3 = LoggerContextNone::getInstance(); // ok
LoggerContext * c4 = c3; // g++ error:
// error: ‘LoggerContext’ is an inaccessible base of ‘LoggerContextNone’
LoggerContext * c5 = LoggerContextNone::getInstance(); // g++ error:
// error: ‘LoggerContext’ is an inaccessible base of ‘LoggerContextNone’
return 0;
}
#包括
#包括
#包括
使用名称空间std;
枚举类日志区域{
记录器\u无,记录器\u下载,记录器\u计算,
};
类ELoggerContext:std::runtime\u错误{
使用std::runtime\u error::runtime\u error;
};
类LoggerContextNone;
类LoggerContext{
受保护的:
LoggerArea mLA;
类LoggerContextNone_AccessToken
{
罗格·康特斯顿朋友;
LoggerContextNone_AccessToken(){}
};
显式LoggerContext(LoggerContextNone_AccessToken):mLA(LoggerArea::LOGGER_NONE){}
公众:
LoggerContext(LoggerArea la);
virtual~LoggerContext(){};
std::string getGeneral();
虚拟std::string getContext()=0;
};
字符串LoggerContext::getGeneral(){
string s=“一般信息:”;
如果(mLA==LoggerArea::LOGGER_NONE){s+=“LOGGER_NONE”;}
else if(mLA==loggerea::LOGGER_下载){s+=“LOGGER_下载”;}
else如果(mLA==loggerea::LOGGER\u COMPUTE){s+=“LOGGER\u COMPUTE”;}
否则{s+=“?”;}
返回s;
}
LoggerContext::LoggerContext(LoggerArea la):
法学硕士(洛杉矶){
if(la==loggerea::LOGGER_NONE){
抛出Elogger上下文(“LOGGER_NONE无法实例化”);
}
}
类LoggerContextNone:LoggerContext{
私人:
LoggerContextNone():LoggerContext(LoggerContextNone_AccessToken()){}
公众:
虚拟~LoggerContextNone()覆盖{
}
虚拟std::string getContext()重写{
返回“”;
}
静态LoggerContextNone*getInstance(){
//这是:
//静态LoggerContextNone&getInstance(){
静态LoggerContextNone实例{};
返回&实例;
}
};
类LoggerContext派生:公共LoggerContext{
公众:
LoggerContextDerived(loggerareala):LoggerContext(la){};
虚拟std::string getContext()重写{
返回“派生上下文”;
}
virtual~LoggerContextDerived()重写{
}
};
int main(){
//测试1:派生类
LoggerContext派生c1{LoggerArea::LOGGER_DOWNLOAD};//确定
CUT感谢您的长时间回复,但它是因为某些东西仍然没有与构造函数一起工作,请参阅我的问题编辑。@ LICOO是一个相当无关的问题。您不能使用基类CCTR来构造C++中的派生类。如果您想在派生类中使用一个PARAM CCTR,则需要在那里定义这样的Cor。构造函数继承(使用LoggerContext::loggercontent)
class LoggerContext
{
protected:
class LoggerContextNone_AccessToken
{
friend LoggerContextNone;
LoggerContextNone_AccessToken() {}
};
explicit LoggerContext(LoggerContextNone_AccessToken) : mLA(LOGGER_NONE) {}
protected:
// ... the rest as before
};
LoggerContextNone::LoggerContextNone() : LoggerContext(LoggerContextNone_AccessToken())
{}
#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() {};
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() {
// this was:
// static LoggerContextNone& getInstance() {
static LoggerContextNone instance {};
return &instance;
}
};
class LoggerContextDerived : public LoggerContext {
public:
LoggerContextDerived(LoggerArea la):LoggerContext(la) { };
virtual std::string getContext() override {
return "derived context";
}
virtual ~LoggerContextDerived() override {
}
};
int main() {
// test 1: derived class
LoggerContextDerived c1 {LoggerArea::LOGGER_DOWNLOAD}; // ok
cout << "General : " << c1.getGeneral() << endl; // ok
cout << "Context : " << c1.getContext() << endl; // ok
LoggerContext * c2 = &c1; // ok
// test 2: derived none class
LoggerContextNone * c3 = LoggerContextNone::getInstance(); // ok
LoggerContext * c4 = c3; // g++ error:
// error: ‘LoggerContext’ is an inaccessible base of ‘LoggerContextNone’
LoggerContext * c5 = LoggerContextNone::getInstance(); // g++ error:
// error: ‘LoggerContext’ is an inaccessible base of ‘LoggerContextNone’
return 0;
}