¿Es el corte de objetos que ocurre al asignar un objeto derivado a través de una referencia de clase base (sin un operator=) virtual una operación bien definida? Es decir, ¿está garantizado por el estándar dejar intactas las partes derivadas del objeto?

En muchas preguntas sobre el corte de objetos aquí y en otros lugares, se da un ejemplo como el siguiente:

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)
}

El ejemplo pretende mostrar que cuando se asigna a través de un Base& solo asigna a los miembros de la clase Base y deja a los miembros en Derived intactos.

Construir el ejemplo anterior con -fsanitize=undefined no se queja, y produce el resultado esperado en todos los sistemas que lo he ejecutado.

La pregunta es, ¿está garantizado por la norma? En mi opinión, es así, ya que Base::operator= no puede escribir fuera de la parte Base del objeto, y la parte Derived del objeto (aquí int y) no puede tener ninguna superposición con la parte Base.

¿Hay algún caso de esquina que me estoy perdiendo? (Por supuesto, hay muchas maneras de tener un objeto inconsistente puede conducir a un comportamiento indefinido, pero mi pregunta se limita a lo que sucede durante la operación de asignación).

1
drRobertz 27 abr. 2020 a las 13:57

2 respuestas

La mejor respuesta
Base& br = d1;

Esto crea una referencia a un objeto Base. Esto ahora hará referencia a un objeto Base que está tan bien formado como cualquier otro objeto Base (en un programa C ++ bien formado). En todos los aspectos, el objeto Base al que se hace referencia es idéntico a todos los demás objetos Base que pueden existir o no. Este objeto puede asignarse como cualquier otro objeto Base, y exactamente lo mismo sucederá con este objeto que con cualquier otro objeto Base al que se asigne. El fin.

Los objetos que son objetos base de otros objetos no son diferentes de los objetos que no lo son, cuando se ven a través del prisma de esos objetos solos. Son objetos propios bien formados, y son como cualquier otro objeto Base (ignorando cosas como los métodos virtuales aquí). Este es un concepto fundamental en C ++.

Sería bastante inconveniente si la asignación a un objeto Base de repente "escribe" en otro lugar. Sería bastante difícil lograr algo en C ++, en ese caso. Por supuesto, no hace falta decir que siempre se puede sobrecargar operator=, y luego el cielo es el límite. Pero desde un punto práctico, siempre que el operador = funcione de la manera que se espera que funcione, la asignación a un objeto Base no hará nada a nada que no sea parte de ese {{X3} } objeto.

3
Sam Varshavchik 27 abr. 2020 a las 11:05

¿Se divide bien el objeto mediante la asignación a través de una referencia base bien definida?

Si. Rebanar es una operación bien definida.

¿está garantizado por el estándar dejar intactas las partes derivadas del objeto?

El operador de asignación generado implícitamente de la base no tocará las partes derivadas. Uno personalizado podría hacerlo, aunque dicho diseño es poco común.

1
eerorika 27 abr. 2020 a las 11:06