Является ли разделение объекта путем назначения через базовую ссылку хорошо определенным? - PullRequest
1 голос
/ 27 апреля 2020

Является ли разделение объекта, которое происходит при назначении производного объекта через ссылку на базовый класс (без виртуального 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 и оставляет членов в Derived нетронутыми.

Создание приведенного выше примера с помощью -fsanitize=undefined не приводит к пожаловаться, и он выдает ожидаемый результат на всех системах, где я его запускаю.

Вопрос в том, гарантируется ли это стандартом? В моем понимании это так: Base::operator= не может писать вне части Base объекта, а часть Derived объекта (здесь int y) не может перекрываться с частью Base.

Есть какой-то угловой чемодан, который мне не хватает? (Конечно, существует множество способов, с помощью которых несовместимый объект может привести к неопределенному поведению, но мой вопрос ограничен тем, что происходит во время операции присваивания.)

Ответы [ 2 ]

3 голосов
/ 27 апреля 2020
Base& br = d1;

Создает ссылку на Base объект. Теперь это будет ссылаться на объект Base, который так же хорошо сформирован, как и любой другой объект Base (в правильно сформированной программе C ++). Во всех отношениях упомянутый объект Base идентичен всем другим Base объектам, которые могут существовать или не существовать. Этот объект может быть назначен так же, как любой другой объект Base, и с этим объектом произойдет то же самое, что и с любым другим объектом Base, которому назначен. Конец.

Объекты, которые являются базовыми объектами других объектов, ничем не отличаются от объектов, которые не являются, если смотреть через призму только этих объектов. Они являются правильно сформированными объектами и похожи на любой другой объект Base (здесь игнорируются такие вещи, как виртуальные методы). Это фундаментальная концепция в C ++.

Было бы довольно неудобно, если бы назначение базовому объекту внезапно «записывало» куда-то еще. В таком случае было бы довольно сложно выполнить что-либо в C ++. Конечно, само собой разумеется, что всегда можно перегрузить operator=, и тогда небо - предел. Но с практической точки зрения, пока оператор = работает так, как ожидается, назначение объекта Base ничего не изменит с чем-либо, что не является частью этого объекта Base.

1 голос
/ 27 апреля 2020

Является ли разделение объекта путем назначения через базовую ссылку хорошо определенным?

Да. Разрезание - это хорошо определенная операция.

Стандарт гарантирует, что оставленные производные части объекта остаются нетронутыми? тронут производные части. Это можно сделать на заказ, хотя такой дизайн встречается редко.

...