c++ - Wt::Dbo 中的循环依赖

标签 c++ wt wt-dbo

Wt 建议使用前向声明以避免循环依赖。

// Settings.h
#include <Wt/Dbo/Dbo.h>
#include <string>

class User; // Forward declaration of User Wt::Dbo object

class Settings 
{
public:
  Wt::Dbo::ptr<User> user;

  template<class Action>
  void persist(Action& a)
  {
    Wt::Dbo::belongsTo(a, user);
  }
};

 

// User.h
#include <Wt/Dbo/Dbo.h>
#include <string>

#include "Settings.h"

class User
{
public:
  Wt::Dbo::weak_ptr<Settings> settings;

  template<class Action>
  void persist(Action& a)
  {
    Wt::Dbo::hasOne(a, settings);
  }
};

但是,当我在另一个 cpp 文件中使用此 Settings 类时,程序无法编译:

// test.cpp
#include "Settings.h"

error: C2079: 'dummy' uses undefined class 'User'

可能的解决方案(我不喜欢)

  1. 解决方案是在每个包含 Settings.h 的 cpp 文件中包含 User.h,即:

    // test.cpp
    #include "User.h"
    #include "Settings.h"
    

    我不喜欢这种解决方案,因为每次包含 Settings.h 时我都必须记住包含 User.h

  2. 另一种解决方案是使用不推荐的 DBO_EXTERN_TEMPLATES 宏,即

    // Settings.h
    ...
    class Settings
    {
    public:
       ....
    };
    
    DBO_EXTERN_TEMPLATES(Settings)
    

    我不喜欢这个解决方案,因为这个宏不被推荐,也不被记录。 DBO_EXTERN_TEMPLATES 并不适用于所有编译器。

问题

a.克服 Wt::Dbo 对象之间的循环依赖关系以避免提到的 undefined class 错误的最佳/首选方法是什么?

b. 为什么解决方案 1. 有效?

我创建了一个新的(一般 - 不是 Wt::Dbo 特定)问题(带有 MCVE),以澄清具体情况:When are member functions of a templated class instantiated?

引用文献

最佳答案

我不熟悉 Wt::Dbo,但我不认为这个问题是它特有的。这更像是一个一般的 C++ 类设计问题,您需要解决/处理它;它实际上在 C++ 项目中相当常见。

对于“最佳/首选方法”,这确实是一个意见问题。在您的情况下,如果您仍然有前向声明,您实际上可以让 User.hSettings.h 相互包含。

例如,在Settings.h中:

// include guard
class User;
#include "User.h"

class Settings { ... };

然后在User.h中,您可以执行以下操作:

// include guard
class Settings;
#include "Settings.h"

class User { ... };

我知道这看起来很奇怪,但这是一种确保您不必始终包含两个 header 的方法。或者,您只需在一个 header 中执行此操作,并确保您始终包含该 header 。

一般来说,我更喜欢的方式是,在头文件中,只包含头文件中绝对需要的内容,然后向前声明其余的内容。然后,我在源文件中包含实际需要的 header 。这样做的原因是,如果我需要更改一个头文件,我不必重新编译包含该头文件的所有源文件;它提高了编译过程的性能。

至于您关于为什么解决方案 1 有效的问题,这是因为您包含文件的方式。在该特定示例中,您甚至不需要在源文件中包含 Settings.h,因为 User.h 已经这样做了。但是,让我们看看预处理器处理完毕后它会是什么样子。

当您包含User.h时,它首先包含Settings.h。包含基本上将内容复制到发生包含的当前文件中。因此,实际上,您的 User.h 看起来像这样:

// User.h
#include <Wt/Dbo/Dbo.h> // contents from this would be here
#include <string> // contents from this would be here

// Settings.h
#include <Wt/Dbo/Dbo.h> // contents NOT included, due to previous include and include guards
#include <string> // same as above

class User; // Forward declaration of User Wt::Dbo object

class Settings 
{
public:
  Wt::Dbo::ptr<User> user;

  template<class Action>
  void persist(Action& a)
  {
    Wt::Dbo::belongsTo(a, user);
  }
};

class User
{
public:
  Wt::Dbo::weak_ptr<Settings> settings;

  template<class Action>
  void persist(Action& a)
  {
    Wt::Dbo::hasOne(a, settings);
  }
};

您现在可以看到,当定义 Settings 类时,User 已经被前向声明,并且可以被 Settings 类。当定义User时,它就拥有了可以使用的Settings的完整定义。现在,在您的 test.cpp 文件中,SettingsUser 均已完全定义,因此可以使用。

我希望这有帮助:)

关于c++ - Wt::Dbo 中的循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59428743/

相关文章:

c++ - 在 switch 语句中使用结构

c++ - 使用 Write 成员将 CString 写入 CFile 时每个字符后为空

c++ - Wt布局头痛

c++ - Ubuntu服务器上的C++ Wt框架

c++ - 在 Qt 中使用 Wt

c++ - ORM 事务提交上的 Wt Segfault

c++ - 良好的可移植 SIMD 库

C++ 存储模板结构