【问题标题】:How can I initialise a pointer member to point at its encapsulating instance?如何初始化指针成员以指向其封装实例?
【发布时间】:2014-03-15 20:50:07
【问题描述】:

假设我有以下情况:

class A; // forward declaration

class A {
public:
    A(A* parent) : parent(parent) {}
    A* parent;
    virtual void foo() = 0;
};

class B : public A {
public:
    B() : A(this) {}
    void foo() {}
};

当实例化B 类的两个单独实例时,parent 指针在每个实例中都是相同的。知道为什么吗?

编辑:我相信上面的内容现在更接近于我的代码中的模型。

【问题讨论】:

  • this 应该可以正常工作。你能发布实际的错误信息吗?
  • this 的值(对象的地址)在此时完全可以使用,无论对象的内容是否已初始化。
  • 本身没有错误信息,只是该类的两个独立实例指向同一个内存位置。
  • 这可能与在我的实际代码中等效于A 的类是纯虚拟的事实有关吗?
  • 你需要一个拷贝构造函数。两个指向两个相同的对象是缺少复制 ctor 的症状。

标签: c++ pointers initialization this forward-declaration


【解决方案1】:

您需要编写一个复制构造函数。复制实例时不会调用默认构造函数,编译器生成的复制构造函数将从原始实例复制 parent 指针。

A(A const &other) : parent(this) {}

您可能还想编写一个复制赋值运算符,以便在将一个实例分配给另一个实例时保留parent 指针。

另外,考虑从parent 已从默认值更改的实例复制或分配时会发生什么。在这种情况下,副本/受让人是否应该获得与原件相同的父代?如果是这样,您的复制构造函数和赋值运算符将必须检查 parent == this 是否会根据结果而有所不同。将nullptr 用作默认值可能更简单——无论哪种方式,您都需要对没有父级的实例进行特殊处理,但空指针至少可以显而易见没有“真正的”父级尚未分配。

【讨论】:

  • 为了避免编译器消息,我会省略“其他”。
  • 我需要为AB 提供一个复制构造函数吗?或者只是A
  • 也许你对nullptr 的想法是正确的,我只是遵循Disjoint Set data structures 的约定,它提出树的根指向自己,但我认为这与无论如何,根为空。
  • 或者也许你应该让这些类不可复制和不可分配。如果树节点的副本应该与原始节点具有相同的父节点,则应该让该父节点知道它的新子节点,这可能会导致重要的处理(例如重新平衡树),甚至可能不受支持(例如二进制已经有两个孩子的树节点)。另一方面,如果树节点的副本是没有父节点的新根,那么它根本就不是真正的副本,应该使用其他构造函数创建。
  • 我同意,我确实认为这些应该是不可复制和不可分配的。我现在将查找这样做的最佳做法,谢谢。
【解决方案2】:

在类定义后添加分号。您提供的示例中缺少它。编译器有时会为此给出神秘的错误消息。

【讨论】:

  • 不,不是这样,上面的代码示例是我快速手动输入的简化版本 - 缺少尾随 ; 是我的错误,但不是我的问题。
猜你喜欢
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多