如何通过 `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