在 C++ 中定义良好的基 class 中是否使用对派生 class 成员的引用?

Is using a reference to a derived class member in its base class well defined in C++?

我正在研究一些代码,它似乎可以工作,但我不确定它是否是定义的行为。

我认为其中存在问题,因为 Base 是通过引用 Derived 成员变量构造的 - 在我的理解中,这是在 Base 之后构造的。

我对此做了一些研究,我发现的所有答案都表明 Base 在 Derived 之前构造,并且来自 Derived 构造函数的参数可以转发给 Base 构造函数。

但是 Derived Members 可以安全地转发给 Base Constructor 吗? Base 中的构造函数和析构函数甚至成员函数是否可以处理无效对象?

这是有问题的简单代码示例:

class Base
{
public:
   Base(SomeClass & obj): m_obj(obj)
   {
       // Does using m_obj here cause problems with a Derived instance?
   }

   virtual ~Base()
   {
       // Does using m_obj here cause problems with a Derived instance?
   }
   
   void SomeMethod()
   {
       // Does using m_obj here cause problems with a Derived instance?
   }
   
private:
   SomeClass & m_obj;
};


class Derived : public Base
{
public:
    Derived():Base(m_derObj){}

private:
    SomeClass m_derObj{123};
};

OnlineGDB

也许我遗漏了 C++ 提供的一些保证 - 或者也许我们很幸运,错误从未发生。

Is using a reference to a derived class member in its base class well defined in C++?

是的。

SomeClass m_derObj(123);

这是无效语法。如果您打算编写默认成员初始化程序,则必须使用大括号或等于初始化程序。

Base(SomeClass & obj): m_obj(obj)
{
    // Does using m_obj here cause problems with a Derived instance?
}

引用的对象尚未初始化,因此您对引用的操作非常有限。

如果您尝试执行此类引用不允许的操作,例如尝试访问引用的对象,则程序的行为是未定义的。如果你不这样做,那就没关系。

virtual ~Base()
{
    // Does using m_obj here cause problems with a Derived instance?
}

引用的对象已经被销毁,因此您可以对引用执行的操作非常有限。

如果您尝试执行此类引用不允许的操作,例如尝试访问引用的对象,则程序的行为是未定义的。如果你不这样做,那就没关系。

void SomeMethod()
{
    // Does using m_obj here cause problems with a Derived instance?
}

根据您用于初始化对象的构造函数,引用可能已变为悬空。在这种情况下,您无法在不导致未定义行为的情况下对引用执行任何操作。此外,如果您从构造函数或析构函数调用该函数,则对象 destroyed/not 尚未构造的问题适用。

但如果引用仍然有效,没关系。

是的,你的预感是正确的。

在构造之前或在销毁之后使用对象具有未定义的行为,最糟糕的未定义行为类型是正常工作的表现。
(你不能通过观看 C++ 程序执行它应该执行的操作而得出它没有未定义行为的结论。)

构造函数可以存储引用但不能以任何方式使用被引用的对象,因为该对象的生命周期尚未开始。

析构函数不能使用该对象,因为它的生命周期已经结束。

您可以在其生命周期内以常规方式在其他成员函数中使用被引用的对象。

这个生命周期问题是避免引用成员的另一个原因。