¿Qué es rebanar objetos?

766
Frankomania 2008-11-09 01:10.

Alguien lo mencionó en el IRC como el problema del corte.

15 answers

635
David Dibben 2008-11-09 01:22.

"Rebanar" es donde se asigna un objeto de una clase derivada a una instancia de una clase base, perdiendo así parte de la información; parte de ella se "corta".

Por ejemplo,

class A {
   int foo;
};

class B : public A {
   int bar;
};

Entonces, un objeto de tipo Btiene dos miembros de datos fooy bar.

Entonces, si tuvieras que escribir esto:

B b;

A a = b;

Entonces la información bsobre el miembro barse pierde en a.

530
fgp 2013-01-23 05:00.

La mayoría de las respuestas aquí no explican cuál es el problema real con el corte. Solo explican los casos benignos de rebanar, no los traicioneros. Suponga, al igual que las otras respuestas, que está tratando con dos clases Ay B, de dónde Bderiva (públicamente) A.

En esta situación, C ++ le permite pasar una instancia del operador de asignación de Bto A(y también al constructor de copia). Esto funciona porque una instancia de Bse puede convertir en a const A&, que es lo que los operadores de asignación y los constructores de copia esperan que sean sus argumentos.

El caso benigno

B b;
A a = b;

No sucede nada malo allí: solicitó una instancia de la Acual es una copia B, y eso es exactamente lo que obtiene. Seguro, ano contendrá algunos de blos miembros, pero ¿cómo debería hacerlo? Es una A, después de todo, no una B, por lo que ni siquiera ha oído acerca de estos miembros, y mucho menos sería capaz de almacenarlos.

El caso traicionero

B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!

Podrías pensar que b2será una copia de b1después. Pero, por desgracia, es no ! Si lo inspecciona, descubrirá que b2es una criatura de Frankenstein, hecha de algunos trozos de b1(los trozos de los que Bhereda A) y algunos trozos de b2(los trozos que solo Bcontiene). ¡Ay!

¿Qué sucedió? Bueno, C ++ por defecto no trata a los operadores de asignación como virtual. Por lo tanto, la línea a_ref = b1llamará al operador de asignación de A, no al de B. Esto se debe a que, para las funciones no virtuales, el tipo declarado (formalmente: estático ) (que es A&) determina qué función se llama, a diferencia del tipo real (formalmente: dinámico ) (que sería B, ya que hace a_refreferencia a una instancia de B) . Ahora, Ael operador de asignación de, obviamente, solo conoce los miembros declarados A, por lo que copiará solo esos, dejando los miembros agregados Bsin cambios.

Una solución

La asignación solo a partes de un objeto generalmente tiene poco sentido, pero C ++, desafortunadamente, no proporciona una forma incorporada de prohibir esto. Sin embargo, puede enrollar el suyo. El primer paso es hacer que el operador de asignación sea virtual . Esto garantizará que siempre se llame al operador de asignación del tipo real , no al tipo declarado . El segundo paso es utilizar dynamic_castpara verificar que el objeto asignado tiene un tipo compatible. El tercer paso es hacer la asignación real en un miembro (¡protegido!) assign(), Ya que B's assign()probablemente querrá usar A' s assign()para copiar A's, miembros.

class A {
public:
  virtual A& operator= (const A& a) {
    assign(a);
    return *this;
  }

protected:
  void assign(const A& a) {
    // copy members of A from a to this
  }
};

class B : public A {
public:
  virtual B& operator= (const A& a) {
    if (const B* b = dynamic_cast<const B*>(&a))
      assign(*b);
    else
      throw bad_assignment();
    return *this;
  }

protected:
  void assign(const B& b) {
    A::assign(b); // Let A's assign() copy members of A from b to this
    // copy members of B from b to this
  }
};

Tenga en cuenta que, por pura conveniencia, B's operator=anula covariablemente el tipo de retorno, ya que sabe que está devolviendo una instancia de B.

158
Black 2008-11-09 01:28.

Si tiene una clase base Ay una clase derivada B, puede hacer lo siguiente.

void wantAnA(A myA)
{
   // work with myA
}

B derived;
// work with the object "derived"
wantAnA(derived);

Ahora el método wantAnAnecesita una copia de derived. Sin embargo, el objeto derivedno se puede copiar por completo, ya que la clase Bpodría inventar variables miembro adicionales que no están en su clase base A.

Por lo tanto, para llamar wantAnA, el compilador "cortará" todos los miembros adicionales de la clase derivada. El resultado podría ser un objeto que no deseaba crear, porque

  • puede estar incompleto,
  • se comporta como un A-objeto ( Bse pierde todo comportamiento especial de la clase ).
42
geh 2014-08-23 08:33.

Todas estas son buenas respuestas. Solo me gustaría agregar un ejemplo de ejecución al pasar objetos por valor vs por referencia:

#include <iostream>

using namespace std;

// Base class
class A {
public:
    A() {}
    A(const A& a) {
        cout << "'A' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am an 'A'" << endl; }
};

// Derived class
class B: public A {
public:
    B():A() {}
    B(const B& a):A(a) {
        cout << "'B' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am a 'B'" << endl; }
};

void g(const A & a) {
    a.run();
}

void h(const A a) {
    a.run();
}

int main() {
    cout << "Call by reference" << endl;
    g(B());
    cout << endl << "Call by copy" << endl;
    h(B());
}

La salida es:

Call by reference
I am a 'B'

Call by copy
'A' copy constructor
I am an 'A'
30
The Archetypal Paul 2008-11-09 01:14.

La tercera coincidencia en Google para "segmentación de C ++" me da este artículo de Wikipedia. http://en.wikipedia.org/wiki/Object_slicing y esto (acalorado, pero las primeras publicaciones definen el problema): http://bytes.com/forum/thread163565.html

Entonces es cuando asigna un objeto de una subclase a la superclase. La superclase no sabe nada de la información adicional en la subclase y no tiene espacio para almacenarla, por lo que la información adicional se "corta".

Si esos enlaces no brindan suficiente información para una "buena respuesta", edite su pregunta para hacernos saber qué más está buscando.

29
Walter Bright 2008-11-09 01:56.

El problema de la segmentación es grave porque puede provocar daños en la memoria y es muy difícil garantizar que un programa no lo sufra. Para diseñarlo fuera del lenguaje, las clases que admiten la herencia deben ser accesibles solo por referencia (no por valor). El lenguaje de programación D tiene esta propiedad.

Considere la clase A y la clase B derivada de A. La corrupción de la memoria puede ocurrir si la parte A tiene un puntero p, y una instancia B que apunta p a los datos adicionales de B. Luego, cuando los datos adicionales se cortan, p apunta a basura.

11
Kartik Maheshwari 2018-03-07 23:35.

En C ++, un objeto de clase derivada se puede asignar a un objeto de clase base, pero no es posible al revés.

class Base { int x, y; };

class Derived : public Base { int z, w; };

int main() 
{
    Derived d;
    Base b = d; // Object Slicing,  z and w of d are sliced off
}

La división de objetos ocurre cuando se asigna un objeto de clase derivada a un objeto de clase base, los atributos adicionales de un objeto de clase derivada se cortan para formar el objeto de clase base.

7
Steve Steiner 2008-11-09 07:38.

Entonces ... ¿Por qué es malo perder la información derivada? ... porque el autor de la clase derivada puede haber cambiado la representación de tal manera que cortar la información adicional cambia el valor que representa el objeto. Esto puede suceder si la clase derivada se usa para almacenar en caché una representación que es más eficiente para ciertas operaciones, pero costosa de transformar de nuevo a la representación base.

También pensé que alguien también debería mencionar lo que debe hacer para evitar cortar ... Obtenga una copia de los estándares de codificación C ++, las directrices de 101 reglas y las mejores prácticas. Lidiar con el corte es el # 54.

Sugiere un patrón algo sofisticado para abordar completamente el problema: tenga un constructor de copia protegido, un DoClone virtual puro protegido y un Clone público con una afirmación que le dirá si una clase derivada (adicional) no pudo implementar DoClone correctamente. (El método Clone hace una copia profunda adecuada del objeto polimórfico).

También puede marcar el constructor de copia en la base como explícito, lo que permite el corte explícito si lo desea.

7
ididak 2008-11-09 14:31.

El problema de la división en C ++ surge de la semántica de valor de sus objetos, que se mantuvo principalmente debido a la compatibilidad con las estructuras de C. Necesita usar una referencia explícita o sintaxis de puntero para lograr el comportamiento "normal" del objeto que se encuentra en la mayoría de los otros lenguajes que utilizan objetos, es decir, los objetos siempre se pasan por referencia.

La respuesta corta es que corta el objeto asignando un objeto derivado a un objeto base por valor , es decir, el objeto restante es solo una parte del objeto derivado. Para preservar la semántica del valor, la segmentación es un comportamiento razonable y tiene usos relativamente raros, que no existen en la mayoría de los otros lenguajes. Algunas personas lo consideran una característica de C ++, mientras que muchos lo consideran una de las peculiaridades / fallas de C ++.

6
haberdar 2012-01-29 08:00.

1. LA DEFINICIÓN DE PROBLEMA DE REBANADO

Si D es una clase derivada de la clase base B, entonces puede asignar un objeto de tipo Derived a una variable (o parámetro) de tipo Base.

EJEMPLO

class Pet
{
 public:
    string name;
};
class Dog : public Pet
{
public:
    string breed;
};

int main()
{   
    Dog dog;
    Pet pet;

    dog.name = "Tommy";
    dog.breed = "Kangal Dog";
    pet = dog;
    cout << pet.breed; //ERROR

Aunque se permite la asignación anterior, el valor que se asigna a la variable mascota pierde su campo de raza. A esto se le llama el problema del corte .

2. CÓMO SOLUCIONAR EL PROBLEMA DEL REBANADO

Para vencer el problema, usamos punteros a variables dinámicas.

EJEMPLO

Pet *ptrP;
Dog *ptrD;
ptrD = new Dog;         
ptrD->name = "Tommy";
ptrD->breed = "Kangal Dog";
ptrP = ptrD;
cout << ((Dog *)ptrP)->breed; 

En este caso, no se perderá ninguno de los miembros de datos o funciones miembro de la variable dinámica a la que apunta ptrD (objeto de clase descendiente). Además, si necesita utilizar funciones, la función debe ser una función virtual.

4
Minok 2009-07-25 09:45.

Me parece que la división no es un problema tanto más que cuando sus propias clases y programas están mal diseñados / diseñados.

Si paso un objeto de subclase como parámetro a un método, que toma un parámetro de tipo superclase, ciertamente debería ser consciente de eso y saber internamente, el método llamado funcionará solo con el objeto de superclase (también conocido como clase base).

Me parece que solo la expectativa irrazonable de que proporcionar una subclase donde se solicita una clase base, de alguna manera daría como resultado resultados específicos de subclase, causaría que el corte sea un problema. Es un diseño deficiente en el uso del método o una implementación de subclase deficiente. Supongo que suele ser el resultado de sacrificar un buen diseño de programación orientada a objetos en favor de la conveniencia o la mejora del rendimiento.

3
Dude 2012-10-18 17:22.

Bien, lo intentaré después de leer muchas publicaciones que explican el corte de objetos, pero no cómo se vuelve problemático.

El escenario vicioso que puede resultar en la corrupción de la memoria es el siguiente:

  • La clase proporciona asignación (accidentalmente, posiblemente generada por el compilador) en una clase base polimórfica.
  • El cliente copia y corta una instancia de una clase derivada.
  • El cliente llama a una función de miembro virtual que accede al estado cortado.
3
Santosh 2014-03-13 08:08.

Cortar significa que los datos agregados por una subclase se descartan cuando un objeto de la subclase se pasa o se devuelve por valor o desde una función que espera un objeto de clase base.

Explicación: considere la siguiente declaración de clase:

           class baseclass
          {
                 ...
                 baseclass & operator =(const baseclass&);
                 baseclass(const baseclass&);
          }
          void function( )
          {
                baseclass obj1=m;
                obj1=m;
          }

Como las funciones de copia de la clase base no saben nada sobre el derivado, solo se copia la parte base del derivado. Esto se conoce comúnmente como rebanar.

1
quidkid 2012-11-30 02:32.
class A 
{ 
    int x; 
};  

class B 
{ 
    B( ) : x(1), c('a') { } 
    int x; 
    char c; 
};  

int main( ) 
{ 
    A a; 
    B b; 
    a = b;     // b.c == 'a' is "sliced" off
    return 0; 
}
1
Sorush 2020-09-13 01:27.

Veo que todas las respuestas mencionan cuando la división de objetos ocurre cuando se cortan los miembros de datos. Aquí doy un ejemplo de que los métodos no se anulan:

class A{
public:
    virtual void Say(){
        std::cout<<"I am A"<<std::endl;
    }
};

class B: public A{
public:
    void Say() override{
        std::cout<<"I am B"<<std::endl;
    }
};

int main(){
   B b;
   A a1;
   A a2=b;

   b.Say(); // I am B
   a1.Say(); // I am A
   a2.Say(); // I am A   why???
}

B (objeto b) se deriva de A (objeto a1 y a2). by a1, como esperamos, llaman a su función miembro. Pero desde el punto de vista del polimorfismo, no esperamos que a2, que es asignado por b, no sea anulado. Básicamente, a2 solo guarda una parte de clase A de b y eso es la división de objetos en C ++.

Para resolver este problema, se debe utilizar una referencia o un puntero.

 A& a2=b;
 a2.Say(); // I am B

o

A* a2 = &b;
a2->Say(); // I am B

Para más detalles, vea mi publicación.

MORE COOL STUFF

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

¿Caduca el repelente de insectos?

¿Caduca el repelente de insectos?

¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?

Se revela la estatua de Godzilla más nueva de Tokio

Se revela la estatua de Godzilla más nueva de Tokio

Anteriormente, Kotaku informó que un hotel Godzilla se estaba abriendo en Tokio este abril. Junto al hotel, estaba programada la aparición de una enorme cabeza de 'Zilla, pero todo lo que hemos visto fueron imágenes conceptuales computarizadas.

El alcalde de Chicago realmente quiere que Elon Musk perfore un túnel debajo de la ciudad

El alcalde de Chicago realmente quiere que Elon Musk perfore un túnel debajo de la ciudad

Foto: Getty Desde que lanzó The Boring Company hace un año, Elon Musk ha mencionado varios sitios de construcción posibles para el negocio de perforación de túneles y ha descartado una vaga referencia a una aprobación gubernamental "verbal" para un túnel Hyperloop que conecta la ciudad de Nueva York y Washington. , CC. Pero ahora sabemos que al menos un alcalde quiere que Musk perfore un agujero debajo de su ciudad.

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.

Cuéntanos tus mejores trucos de Washington, DC

Cuéntanos tus mejores trucos de Washington, DC

Hemos pirateado algunas ciudades industriales en esta columna, como Los Ángeles y Las Vegas. Ahora es el momento de una ciudad militar-industrial-compleja.

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.

India me está pateando el culo

India me está pateando el culo

Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

¿Merrick Garland le ha fallado a Estados Unidos?

Es más de la mitad de la presidencia de Biden. ¿Qué está esperando Merrick Garland?

¿Merrick Garland le ha fallado a Estados Unidos?

Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.

Language