2012-06-16 11 views
11

¿Qué sucede en el siguiente ejemplo?Referencia de clase base: asigne otro tipo a ella

struct B { }; 
struct D1 : B { }; 
struct D2 : B { }; 
int main() 
{ 
    D1 d; 
    D2 d2; 
    B& x = d; 
    x = d2; 
} 

Sé que la referencia no se reasigna. x todavía se refiere a d, pero ¿cómo se puede asignar d2 a d?

Algunos más:

struct B 
{ 
    B() { x = 0; } 
    int x; 
    virtual void foo() { cout << "B" << endl; } 
}; 
struct D1 : B 
{ 
    D1() { x = 1; } 
    virtual void foo() { cout << "D1" << endl; } 
}; 
struct D2 : B 
{ 
    D2() { x = 2; } 
    virtual void foo() { cout << "D2" << endl; } 
}; 

int main() 
{ 
D1 d; 
D2 d2; 
B& x = d; 
x.foo(); //D1 
       //x.x is 1 here 
x = d2; 
x.foo(); //also D1 
       //but x.x is 2 here 
} 

Parece que x.x se ha actualizado, pero el vftable no era ... ¿Por qué?

+0

+1. Buena pregunta. – Nawaz

Respuesta

11

x se refiere a la clase B base de subobjeto de d. La asignación x = d2slices el subobjeto base B de d2 y asigna su valor al subobjeto de d.

Esto generalmente no se hace intencionalmente.

EDIT:

Parece que x.x se ha actualizado, pero el vftable no era ... ¿Por qué?

Eso es lo que hace el operador de asignación B::operator=. Las clases base en C++ son totalmente inconscientes de que son clases base. Además, el tipo de un objeto no se puede cambiar durante su vida útil. La alternativa más cercana es C++ 11 std::move, que puede transferir el antiguo objeto B dentro de un D1 en un objeto nuevo D2. Entonces destruirías el objeto viejo.

+0

Hmm, ¿se puede copiar la asignación 'virtual', por cierto? (demasiado perezoso para intentar/buscar) –

+0

Pensé que el uso de referencias evita cortar ... ¿no? – AMCoder

+0

Honestamente, no sabía esto. En realidad, no pensé en esto antes. +1. – Nawaz

1

En su caso, cuando asigne miembros de esta manera, que no pertenecen a la clase Base se cortarán. Lo que significa que en este caso se copia como si estuvieras asignando un objeto de clase Base a otro.

+0

¿Estás hablando de corte de objetos (porque así es como se llama)? – AMCoder

+0

Sí, he olvidado este término. – Spo1ler

3

Si lo desea, puede implementar el = por usted mismo y "evitar" el corte comprobando el tipo concreto apropiado (o dando un error). Vea el ejemplo a continuación con errores.

struct B { 
    virtual B& operator = (B& b) = 0; 
}; 
struct D1 : B { 
    D1& operator = (B& b) { 
    if (dynamic_cast<D1*>(&b) == 0) { 
     cerr << "Cannot assign non D1 to D1" << endl; 
     exit(255); 
    } 
    // handle the assignments 
    return *this; 
    } 
}; 
struct D2 : B { 
    int c; 
    D2& operator = (B& b) { 
    if (dynamic_cast<D2*>(&b) == 0) { 
     cerr << "Cannot assign non D2 to D2" << endl; 
     exit(255); 
    } 
    // handle the assignments 
    return *this; 
    } 
}; 
+0

Creo que está preguntando sobre el comportamiento, no sobre cómo hacerlo ... –

+0

Esto no es lo que estaba pidiendo ... – AMCoder

+0

+1, buena idea, pero 'throw' sería mejor que' exit'. – Potatoswatter

Cuestiones relacionadas