通过基引用分配的对象切片是否定义明确?

Is object slicing by assigning through a base reference well-defined?

通过基 class 引用(没有虚拟 operator=)分配派生对象时发生的对象切片是定义明确的操作吗?即,标准是否保证对象的派生部分保持不变?

在此处和其他地方有关对象切片的许多问题中,给出了如下示例:

struct Base{
    int x;
    Base(int xx) :x(xx) {}
    virtual void print() const {std::cout << "Base("<<x<<")\n";}
};

struct Derived : Base{
    int y;
    Derived(int xx, int yy ) :Base(xx),y(yy){}
    void print() const {std::cout << "Derived("<<x<<","<<y<<")\n";}
};

int main()
{
    Derived d1{1,2};
    Derived d2{3,4};

    Base& br = d1;
    br = d2;     // assign a Derived through a Base&

    br.print();  // prints Derived(3,2)
}

该示例旨在表明,当通过 Base& 分配时,它仅分配 Base class 成员,而 Derived 中的成员保持不变。

使用 -fsanitize=undefined 构建上面的示例不会报错,它会在我 运行 它的所有系统上产生预期的输出。

请问,这个有标准保证吗?在我的理解中,因为 Base::operator= 不能写在对象的 Base 部分之外,并且对象的 Derived 部分(这里是 int y)不能与Base 部分。

我是否遗漏了一些特殊情况? (当然,对象不一致有很多方式会导致未定义的行为,但我的问题仅限于赋值操作期间发生的情况。)

Base& br = d1;

这将创建对 Base 对象的引用。这现在将引用一个 Base 对象,它与任何其他 Base 对象(在一个格式良好的 C++ 程序中)一样格式良好。在所有方面,引用的 Base 对象与可能存在或不存在的所有其他 Base 对象相同。这个对象可以被分配给任何其他 Base 对象,就像可以分配给任何其他 Base 对象一样,这个对象将发生与任何其他被分配给的 Base 对象完全相同的事情。结束。

仅通过这些对象的棱镜观察时,作为其他对象的基础对象的对象与不是其他对象的对象没有任何区别。它们是自己的格式良好的对象,就像任何其他 Base 对象一样(这里忽略虚拟方法之类的东西)。这是 C++ 中的一个基本概念。

突然"writes"在其他地方赋值给一个Base对象会很不方便。在那种情况下,用 C++ 完成任何事情都相当困难。当然,不言而喻,一个人总是可以超载 operator=,然后天空就是极限。但是从实际的角度来看,只要 = 运算符按照预期的方式工作,分配给 Base 对象就不会对不属于 Base 的任何东西做任何事情] 对象。

Is object slicing by assigning through a base reference well-defined?

是的。切片是定义明确的操作。

is it guaranteed by the standard to leave the derived parts of the object untouched?

隐式生成的基类赋值运算符不会触及派生部分。定制的可以这样做,尽管这种设计并不常见。