C++ 中的相互 class 引用

Mutual class references in C++

我公司有一些代码采用以下形式:

class ObjectA {
public:
  ObjectA(ObjectB &objectB): objectB(objectB) { }

void Initialize() { ... }

private:
  ObjectB &objectB;
};

class ObjectB {
public:
  ObjectB(ObjectA &objectA): objectA(objectA) { }

void Initialize() { ... }

private:
  ObjectA &objectA;
};

基本上,两个 class 相互依赖。

这本身并不是困扰我的问题,(尽管 IMO 的设计不是很好)相互依赖是通过构造函数传递的两种情况下的参考.

因此,实际构建这对对象的唯一方法(它们在应用程序中都是必需的) 是传递一个不完整的引用作为依赖项。为了解决这个问题,将单独的 Initialize 方法添加为第二阶段构造函数,然后在创建两个对象后调用它们。因此,构造函数通常除了将构造函数参数分配给对象内部并在 Intizialize 方法中初始化所有内容外什么都不做。

尽管代码可能有效,但我倾向于认为这是一个根本性的缺陷设计,原因如下:

  1. 依赖对象的状态不能在 构造函数
  2. 需要开发者额外调用Initialize
  3. 它排除了使用检查成员变量是否已初始化的编译器警告
  4. 没有什么可以阻止 Initialize 被多次调用,这可能会导致奇怪的、难以追踪的错误

我的同事告诉我,使用单独的初始化方法可以简化对象构造,因为开发人员不必担心在应用程序根目录中声明了哪些顺序对象。它们可以以完全任意的顺序声明和构造,因为一旦调用 Initialize 一切都保证有效。

我一直提倡对象构造应该遵循依赖图的相同顺序,并且应该重新设计这些对象以消除相互依赖,但我想看看 SO 专家对此有何评论。我认为这是不好的做法是错误的吗?

编辑:

这些 classes 实际构建的方式是通过工厂 class 如下所示:

Factory {
public:
  Factory():
    objectA(objectB),
    objectB(objectA) {
  }
private:
  ObjectA objectA;
  ObjectB objectB;
};

是的,这是不好的做法。传递对 objectB 的引用以供 objectA 使用,但它还没有正确初始化,这是一个禁忌。

它现在可能是符合标准且安全的代码,因为 ObjectA 不会尝试在其构造函数中访问传递给 ObjectB 的引用,但安全性被线程挂起。如果稍后有人决定只在构造函数中初始化或访问 objectB 中的任何内容,或以任何其他方式更改它以使用 objectB,你最终会得到 UB。

这听起来像是在两个构造函数都具有 运行.

之后重新安置指针的用例

我也不喜欢发布的代码 - 它不必要地复杂和脆弱。当两个 类 像这样合作时通常会有一些所有权的概念,所以,如果类型 A 的对象拥有类型 B 的对象(他们可能应该),那么你会做一些事情喜欢:

#include <memory>

class A;

class B
{
public:
    B (A& a) : a (a) { }
private:
    A& a;
};

class A
{
public:
    A () { b = std::make_unique <B> (*this); }

private:
    std::unique_ptr <B> b;
}; 

Live demo