如何通过"extern"获取C++中的"global"类对象

How to obtain a "global" class object in C++ via `extern`

本文关键字:global 中的 对象 获取 何通过 extern C++      更新时间:2023-10-16

我在论坛上检查了几个关于这个主题的答案,但由于某种原因,我仍然无法思考这个问题并让我的作品运行。

我的目标是在所有翻译单元中提供类的一个对象。请注意,我不寻求在这里实现单例模式。该类可以有多个实例,但总会至少有一个实例,可以在包含"其标头"的位置看到这个实例。

假设这样的设计:

---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;行?或者只是LogCenter globalCenter; logging.cpp中并extern LogCenter globalCenter;使用它的任何文件中?

真的很困惑,我尝试过的方法都没有奏效 - 但是,当我将构造函数重载与其自己的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 变量是一个选项。

另一种选择是有一个返回引用的函数。

logging.h:

LogCenter& getGlobalLogCenter();

日志记录.cpp:

LogCenter& getGlobalLogCenter()
{
   static LogCenter lc;
   return lc;
}
//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_

三十

// logcenter.cpp
#include "LogCenter.h"
LogCenter globalCenter;

三十

//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

三十

// logger.cpp
#include "Logger.h"
extern LogCenter globalCenter;
Logger::Logger() : center(globalCenter) {};
Logger::Logger(LogCenter &logcenter) : center(logcenter) {};

三十

// 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

我建议您使用以下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();

要回答您关于外部的问题:

// 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类的新对象,但不打算使用globalCenter对象,那么为什么他需要globalCenter对象的extern声明。