如何通过 `extern` 在 C++ 中获取 "global" class 对象
How to obtain a "global" class object in C++ via `extern`
我在论坛上检查了几个关于这个主题的答案,但出于某种原因,我仍然无法解决这个问题并得到我的作品 运行。
我的目标是让 class 的一个对象在所有翻译单元中可用。请注意,我不打算在这里实现单例模式。 class 可以有多个实例,但总是至少有一个 一个 ,这个可以在包含 "its header" 的地方看到。
假设这样的设计:
---logging.h---
class LogCenter {
...
}
class Logger {
private:
LogCenter& center;
public:
Logger(); //automatically assigns the ominous global LogCenter object (reference) to center.
Logger(LogCenter&); //however, any other LogCenter object would work equally fine.
}
原因?我希望所有 Logger
都可以默认使用这个全局 LogCenter
,无论它们在哪里使用。
但是现在我不确定如何提供这个全局 LogCenter
。它有默认的构造函数。我是否只在 logging.h
文件中添加一行 extern LogCenter globalCenter;
并在 logging.cpp
文件中添加另一行 LogCenter globalCenter;
?或者只是 logging.cpp
中的 LogCenter globalCenter;
和任何使用它的文件中的 extern LogCenter globalCenter;
?
我真的很困惑,我试过的 none 有效 - 但是,当我使用构造函数重载及其自己的 LogCenter
实例时,整体代码工作正常。
编辑:重要提示:extern
与声明一起使用(例如在头文件中)。然后在一个实现文件中定义一个。
检查全部个答案!
这是它的工作原理:
---logging.h---
class Entry;
class LogCenter {
friend class Logger; //please don't bash my friend design right away... D:
private:
list<Entry> entries;
public:
void printLog(string file);
}
extern LogCenter SCenter;
class Logger {
private:
LogCenter& center;
public:
Logger(); //uses extern or "singleton" object.
Logger(LogCenter&);
void commitEntry(Entry); //adds the Entry object to the list in the center object.
}
-----------------
---logging.cpp---
#include "logging.h"
LogCenter SCenter;
void Logger::commitEntry(Entry e) {
entries.push_back(e); //Logger can access LogCenter fields!
}
void LogCenter::printLog(string file) {
//open file stream str
for(list<Entry>::iterator it = entries.begin();...)
str << it->getEntry() << endl;
//close file
}
--------------
---main.cpp---
#include "logging.h"
int main() {
Logger log;
Entry e("Some entry");
log.commitEntry(e);
SCenter.printLog("filename.log");
//or
LogCenter cent;
Logger log(cent);
Entry e("some entry");
log.commitEntry(e);
cent.printLog("filename.log");
return 0;
}
-------------
使用 extern
变量是一种选择。
另一种选择是具有 returns 引用的功能。
logging.h:
LogCenter& getGlobalLogCenter();
logging.cpp:
LogCenter& getGlobalLogCenter()
{
static LogCenter lc;
return lc;
}
我建议您使用以下 C++ 单例模式,它易于使用,在跨共享库使用时甚至安全:
// LogCenter.h
class /*API_MACRO_FOR_EXPORTING*/ LogCenter {
public:
static LogCenter* instance();
}
// For quick access you could define a macro
#define sLogCenter \
LogCenter::instance()
// LogCenter.cpp
LogCenter* LogCenter::instance()
{
static LogCenter instance;
return &instance;
}
// LogCenter::instance()->DoSomething();
// sLogCenter->DoSomething();
回答你关于 extern 的问题:
// LogCenter.h
// You can use multiple definitions with extern so the compiler
// knows the LogCenter is instantiated somewhere else.
extern LogCenter globalCenter;
// LogCenter.cpp
// Only 1 declaration of LogCenter
/*API_MACRO_FOR_EXPORTING*/ LogCenter globalCenter;
我会选择第二个选项,即 "extern LogCenter globalCenter;" 在使用它的文件中。
原因,如果有人包含logging.h,可能是为了创建Logcenter的新对象class,但不打算使用globalCenter对象,那么他为什么需要extern声明对于 globalCenter 对象。
//logcenter.h
#ifndef LOGCENTER_H_
#define LOGCENTER_H_
class LogCenter {
private:
int dummy;
public:
int getVal(){ return dummy; };
LogCenter() : dummy(0){};
LogCenter(int val) : dummy(val) {};
};
#endif // LOGCENTER_H_
xxx
// logcenter.cpp
#include "LogCenter.h"
LogCenter globalCenter;
xxx
//logger.h
#ifndef LOGGER_H_
#define LOGGER_H_
#include <string>
#include "LogCenter.h"
class Logger {
private:
LogCenter& center;
public:
Logger(); //automatically assigns the ominous global LogCenter object (reference) to center.
Logger(LogCenter&); //however, any other LogCenter object would work equally fine.
std::string print() { return std::string("This class uses logger ") + std::to_string(center.getVal()); };
};
#endif // LOGCENTER_H
xxx
// logger.cpp
#include "Logger.h"
extern LogCenter globalCenter;
Logger::Logger() : center(globalCenter) {};
Logger::Logger(LogCenter &logcenter) : center(logcenter) {};
xxx
// main.cpp
#include "Logger.h"
int main(int argc, char* argv[])
{
LogCenter logcenter2(2), logcenter3(3);
Logger logger1, logger2(logcenter2), logger3(logcenter3);
std::cout << logger1.print() << std::endl;
std::cout << logger2.print() << std::endl;
std::cout << logger3.print() << std::endl;
return 0;
}
输出为:
This class uses logger 0
This class uses logger 2
This class uses logger 3
我在论坛上检查了几个关于这个主题的答案,但出于某种原因,我仍然无法解决这个问题并得到我的作品 运行。
我的目标是让 class 的一个对象在所有翻译单元中可用。请注意,我不打算在这里实现单例模式。 class 可以有多个实例,但总是至少有一个 一个 ,这个可以在包含 "its header" 的地方看到。
假设这样的设计:
---logging.h---
class LogCenter {
...
}
class Logger {
private:
LogCenter& center;
public:
Logger(); //automatically assigns the ominous global LogCenter object (reference) to center.
Logger(LogCenter&); //however, any other LogCenter object would work equally fine.
}
原因?我希望所有 Logger
都可以默认使用这个全局 LogCenter
,无论它们在哪里使用。
但是现在我不确定如何提供这个全局 LogCenter
。它有默认的构造函数。我是否只在 logging.h
文件中添加一行 extern LogCenter globalCenter;
并在 logging.cpp
文件中添加另一行 LogCenter globalCenter;
?或者只是 logging.cpp
中的 LogCenter globalCenter;
和任何使用它的文件中的 extern LogCenter globalCenter;
?
我真的很困惑,我试过的 none 有效 - 但是,当我使用构造函数重载及其自己的 LogCenter
实例时,整体代码工作正常。
编辑:重要提示:extern
与声明一起使用(例如在头文件中)。然后在一个实现文件中定义一个。
检查全部个答案!
这是它的工作原理:
---logging.h---
class Entry;
class LogCenter {
friend class Logger; //please don't bash my friend design right away... D:
private:
list<Entry> entries;
public:
void printLog(string file);
}
extern LogCenter SCenter;
class Logger {
private:
LogCenter& center;
public:
Logger(); //uses extern or "singleton" object.
Logger(LogCenter&);
void commitEntry(Entry); //adds the Entry object to the list in the center object.
}
-----------------
---logging.cpp---
#include "logging.h"
LogCenter SCenter;
void Logger::commitEntry(Entry e) {
entries.push_back(e); //Logger can access LogCenter fields!
}
void LogCenter::printLog(string file) {
//open file stream str
for(list<Entry>::iterator it = entries.begin();...)
str << it->getEntry() << endl;
//close file
}
--------------
---main.cpp---
#include "logging.h"
int main() {
Logger log;
Entry e("Some entry");
log.commitEntry(e);
SCenter.printLog("filename.log");
//or
LogCenter cent;
Logger log(cent);
Entry e("some entry");
log.commitEntry(e);
cent.printLog("filename.log");
return 0;
}
-------------
使用 extern
变量是一种选择。
另一种选择是具有 returns 引用的功能。
logging.h:
LogCenter& getGlobalLogCenter();
logging.cpp:
LogCenter& getGlobalLogCenter()
{
static LogCenter lc;
return lc;
}
我建议您使用以下 C++ 单例模式,它易于使用,在跨共享库使用时甚至安全:
// LogCenter.h
class /*API_MACRO_FOR_EXPORTING*/ LogCenter {
public:
static LogCenter* instance();
}
// For quick access you could define a macro
#define sLogCenter \
LogCenter::instance()
// LogCenter.cpp
LogCenter* LogCenter::instance()
{
static LogCenter instance;
return &instance;
}
// LogCenter::instance()->DoSomething();
// sLogCenter->DoSomething();
回答你关于 extern 的问题:
// LogCenter.h
// You can use multiple definitions with extern so the compiler
// knows the LogCenter is instantiated somewhere else.
extern LogCenter globalCenter;
// LogCenter.cpp
// Only 1 declaration of LogCenter
/*API_MACRO_FOR_EXPORTING*/ LogCenter globalCenter;
我会选择第二个选项,即 "extern LogCenter globalCenter;" 在使用它的文件中。
原因,如果有人包含logging.h,可能是为了创建Logcenter的新对象class,但不打算使用globalCenter对象,那么他为什么需要extern声明对于 globalCenter 对象。
//logcenter.h
#ifndef LOGCENTER_H_
#define LOGCENTER_H_
class LogCenter {
private:
int dummy;
public:
int getVal(){ return dummy; };
LogCenter() : dummy(0){};
LogCenter(int val) : dummy(val) {};
};
#endif // LOGCENTER_H_
xxx
// logcenter.cpp
#include "LogCenter.h"
LogCenter globalCenter;
xxx
//logger.h
#ifndef LOGGER_H_
#define LOGGER_H_
#include <string>
#include "LogCenter.h"
class Logger {
private:
LogCenter& center;
public:
Logger(); //automatically assigns the ominous global LogCenter object (reference) to center.
Logger(LogCenter&); //however, any other LogCenter object would work equally fine.
std::string print() { return std::string("This class uses logger ") + std::to_string(center.getVal()); };
};
#endif // LOGCENTER_H
xxx
// logger.cpp
#include "Logger.h"
extern LogCenter globalCenter;
Logger::Logger() : center(globalCenter) {};
Logger::Logger(LogCenter &logcenter) : center(logcenter) {};
xxx
// main.cpp
#include "Logger.h"
int main(int argc, char* argv[])
{
LogCenter logcenter2(2), logcenter3(3);
Logger logger1, logger2(logcenter2), logger3(logcenter3);
std::cout << logger1.print() << std::endl;
std::cout << logger2.print() << std::endl;
std::cout << logger3.print() << std::endl;
return 0;
}
输出为:
This class uses logger 0
This class uses logger 2
This class uses logger 3