【问题标题】:C++ cpp files as modulesC++ cpp 文件作为模块
【发布时间】:2016-12-28 18:24:38
【问题描述】:

对不起,如果我重复其他问题,但我不知道如何用谷歌搜索它。 我想为我的程序添加一些小的模块化:一些 .cpp 文件应该编译为“模块”。主要要求是我应该能够通过将新的 .cpp 文件添加到项目中来添加模块,而无需以任何方式更改其他文件。

使用动态加载库实现这一点看起来很容易。主程序可以扫描某个文件夹中的所有 .dll 文件,加载每个文件并从每个模块调用导出的“加载”符号。在析构函数中,主程序可以调用“卸载”符号,以便模块可以清理。

我想要同样的,但使用单片程序。 .cpp 文件有什么方法可以注册自己,以便主程序可以在某个时候调用它们的 init() 函数?或者让主程序找到所有这些模块?

它在Linux内核中是如何完成的?我知道简单的添加 .c 文件可以让它们以某种方式工作。

【问题讨论】:

  • 你可以静态链接一切吗?
  • 从我的跟踪来看,.cpp 文件无法将自身添加到 main,所有 .cpp 文件都需要附加某种形式的头文件...您可以查看:tutorialspoint.com/cplusplus/cpp_inheritance.htm举个例子……
  • "所有的.cpp文件都需要附加某种形式的头文件"主程序可以暴露一个注册接口。
  • “在 Linux 内核中是如何完成的?我知道简单的添加 .c 文件可以让它们以某种方式工作。” 内核模块需要编译为模块才能添加它.这些内核模块需要提供特定的接口才能使其正常工作。
  • @πάνταῥεῖ "如果添加了新的内核模块,需要重新编译内核" 是吗? modprobe呢?

标签: c++ modularity


【解决方案1】:

您可以在每个 cpp 文件中使用静态虚拟变量,并通过 lambda 进行初始化和注册来对其进行初始化。简单的例子:

// registration.h

void register_cpp (std::string name);
void print_cpps ();

// registration.cpp
namespace {
   std::vector<std::string> & names () {
      static std::vector<std::string> names_ {};
      return names_;
   }
}

void register_cpp (std::string name) {
   names ().push_back (name); // well, push_back(std::move (name)) would be more efficient
}

void print_cpps () {
    for (auto && name : names()) { std::cout << name << "\n"; }
}

// a.cpp

#include "registration.h"
static std::nullptr_t e = ([] () { register_cpp ("a"); return nullptr; }) ();

// b.cpp

#include "registration.h"
static std::nullptr_t e = ([] () { register_cpp ("b"); return nullptr; }) ();

// main.cpp
#include "registration.h"
int main () {
   print_cpps ();
   return 0;
}

我认为您需要将 names_ 作为静态局部变量,以确保在第一次访问之前对其进行初始化。

【讨论】:

    【解决方案2】:

    您可以使用从主应用程序(单例)公开的注册接口将新的.cpp 文件添加到静态链接的应用程序,而无需更改现有代码。

    有点像

    应用程序.h:

     struct IModule {
         virtual void init() = 0;
         virtual ~IModule() {}
     };
    
     class App {
     public:
          void registerModule(IModule* newModule); // Stores the interface
                                                   // pointer of an additional
                                                   // module
          static App& instance() {
               static App theInstance;
               return theInstance;
          }
     };
    

    NewModule.cpp:

     #include "App.h"
    
     class NewModule : public IModule {
     public:
          void init();
     private:
          NewModule() {
              App::getInstance().registerModule(this);
          }
    
          static NewModule instance;
     };
    
     NewModule NewModule::instance;
    

    【讨论】:

    • 谢谢!我需要测试一下!我了解 NewModule.cpp 但不完全确定我了解 App 类......它是某种单例吗?它是如何初始化的..?需要一些时间...再次感谢!
    • @Sion0 是的,正如我所提到的,它是一个 Singleton。初始化为static App theInstance;
    • 我不知道 C++11 是否发生了变化,但我很久以前就使用过这个范例,并且 AFAIK 链接器忽略了 NewModule::instance 看到它没有在任何地方明确使用,所以我们不得不添加一些代码,例如 forceLink,它们只引用这些静态实例,以强制链接器构造它们,以便它们自己注册。
    • @A.S.H 也许这是必要的,IDK。但据我所知,例如 google 测试测试类以类似的方式工作,我不需要指定这样的链接器选项。
    • 看起来像预期的那样工作,谢谢。我还试图弄清楚如何在 Linux 内核中实现模块注册,但我对这些事情还不够酷。 link - 关于符号导出...
    猜你喜欢
    • 2019-04-14
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    • 2021-02-23
    相关资源
    最近更新 更多