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