You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++多重继承层级问题:构造初始化与未定义行为疑问

多重继承构造初始化问题分析

问题代码

#include <iostream>

struct Parent
{
    virtual ~Parent() = default;
};

class Buddy
{
public:
    virtual ~Buddy() = default;
    Buddy(Parent& p) : parent_ { p } {}
    bool IsHovered() const { return is_hovered_; }

private:
    bool    is_hovered_ = false;
    Parent& parent_;
};

class Child : public Parent, public Buddy
{
public:
    Child() : Buddy { *this } {}

    bool BuddyIsHovered() const { return IsHovered(); }
};

int main()
{
    Child c;
    // 预期输出false,但实际总是输出true
    std::cout << std::boolalpha << c.BuddyIsHovered() << '\n';
}

假设验证

我们逐个分析你的三个假设:

  1. 编译器首先为Child分配内存 → 正确。
    在任何构造函数执行之前,程序会先为整个Child对象分配足够的内存空间,包含Parent和Buddy的所有成员及虚函数表指针(vptr),之后才会启动构造流程。

  2. 运行Child构造函数时,编译器已知所有类的正确地址 → 错误。
    在对象构造过程中,尤其是基类初始化阶段,对象的动态类型尚未完全成为Child。当你在Child构造函数中向Buddy传递*this作为Parent&时,虽然Parent基类已完成初始化,但整个Child对象的布局尚未完全确定,此时对*this的类型转换或地址依赖可能触发未定义行为。

  3. 初始化顺序为Parent、Buddy、Child,此时Buddy已初始化,可调用其未涉及未初始化成员的代码 → 部分正确,部分错误。

    • 初始化顺序是正确的:C++规定基类按继承列表顺序初始化(Parent → Buddy),随后初始化Child自身成员(无),最后执行Child构造函数体。
    • 后半句错误:虽然Buddy的构造函数已执行完毕,IsHovered()看似仅访问已初始化的is_hovered_,但由于你在Buddy构造时传递了未完全构造的Child对象(*this),这种操作属于未定义行为范畴——即使代码逻辑上只访问已初始化成员,编译器的优化或内存布局也可能导致成员值被意外篡改(比如你遇到的is_hovered_变为true)。

问题根源

你的代码触发了未定义行为:在Child构造过程中,将未完全构造的*this传递给基类Buddy的构造函数。尽管Parent子对象已初始化,但Child对象本身尚未完成构造,此时将其作为参数传递会导致编译器无法保证对象状态的正确性,最终表现为is_hovered_值不符合预期。

内容的提问来源于stack exchange,提问作者qloq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:55:37