【问题标题】:Is object slicing by assigning through a base reference well-defined?通过基引用进行分配的对象切片是否定义明确?
【发布时间】:2020-04-27 10:57:38
【问题描述】:

通过基类引用(没有虚拟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&amp; 分配时,它仅分配Base 类成员,而保持Derived 中的成员不变。

使用-fsanitize=undefined 构建上述示例不会产生任何问题,它会在我运行过的所有系统上产生预期的输出。

问题是,标准是否保证了这一点?据我了解,因为Base::operator= 不能写在对象的Base 部分之外,并且对象的Derived 部分(此处为int y)不能与Base 部分有任何重叠。

我缺少一些极端情况吗? (当然,有很多不一致的对象会导致未定义的行为,但我的问题仅限于赋值操作期间发生的情况。)

【问题讨论】:

    标签: c++ inheritance reference language-lawyer object-slicing


    【解决方案1】:
    Base& br = d1;
    

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

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

    如果分配给 Base 对象突然“写入”到其他地方会很不方便。在这种情况下,用 C++ 完成任何事情都是相当困难的。当然,不言而喻,operator= 总是可以超载,然后天空就是极限。但从实际的角度来看,只要 = 运算符按照预期的方式工作,分配给 Base 对象不会对不属于该 Base 对象的任何内容执行任何操作。

    【讨论】:

      【解决方案2】:

      通过基引用进行分配的对象切片是否定义良好?

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

      标准是否保证对象的派生部分不受影响?

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

      【讨论】:

        猜你喜欢
        • 2015-11-07
        • 1970-01-01
        • 1970-01-01
        • 2015-10-03
        • 1970-01-01
        • 1970-01-01
        • 2016-12-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多