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