2010-11-29 18 views
6

Estaba escribiendo un operador == entre dos tipos de puntero inteligente y pensé que debería ejecutar una comprobación de cordura rápida. Estoy sorprendido por el resultado ...¿Cómo pueden los punteros de las subclases ser estrictamente iguales a los punteros de clase padre?

En el siguiente fragmento, ¿cómo es que todas las variantes de f y b terminan con el mismo valor?

struct Foo { 
    int x; 
}; 

struct Bar : public Foo { 
    int y; 
}; 

#include <iostream> 

int main() 
{ 
    Bar bar; 

    Foo * f = &bar; 
    Bar * b = &bar; 
    std :: cout << f << " " << b << " " << (f == b) << "\n"; 

    void * fv = f; 
    void * bv = b; 
    std :: cout << fv << " " << bv << " " << (fv == bv) << "\n"; 

    int fi = reinterpret_cast <int> (f); 
    int bi = reinterpret_cast <int> (b); 
    std :: cout << fi << " " << bi << " " << (fi == bi) << "\n"; 
} 
+0

Por cierto, el objetivo original fue verificar que la expresión (f == b) es equivalente a (f == (Foo *) b) - Necesito esta conversión implícita para que se comporte adecuadamente con las plantillas. – spraff

Respuesta

8

Acerca del único momento en que un objeto de clase base no tendrá la misma dirección que su objeto de subclase cuando se trate de una herencia múltiple.

En el ejemplo anterior, probablemente, la memoria se parece a esto:

 
          /--------- \ 
          /| x  | > This is the Foo portion of bar 
This is the whole Bar object < ---------/ 
           \ | y  | 
           \ --------- 

Ambos puntos de vista del objeto no tienen el mismo punto de partida, por lo que un puntero a ambos puntos de vista tendrá el mismo valor.

En la herencia múltiple, las cosas se vuelven más complicadas. Digamos que tiene:

struct Foo1{ int x; }; 
struct Foo2{ int y; }; 
struct Bar : public Foo1, public Foo2 { int z; }; 
Bar bar; 

Ahora la memoria tendrá que ser expuesto algo como esto:

 
           /--------- \ 
          /| x  | > This is the Foo1 portion of bar 
          / ---------/\ 
This is the whole Bar object < | y  | > This is the Foo2 portion of bar 
           \ --------- /
           \ | z  | 
           \ --------- 

Así &bar y (Foo1*)&bar tendrá el mismo valor, mientras que (Foo2*)&bar tendrá un valor diferente, ya si la parte Foo2 del objeto comienza en una dirección más alta.

+0

1 de ASCII más agradable que la mía :) –

2

Ésta es la disposición de memoria típica que va a terminar con:

Bar starts Foo starts x starts/ends Foo ends y starts/ends Bar ends 
|   |    |    |   | |    |   | 

Sice no hay nada entre la barra de inicio y Foo empezar, el desplazamiento de Foo puede ser cero, por lo tanto, los punteros para Bar , Foo yx podrían ser idénticos.

+0

No realmente, no. –

+0

@Noah Bien, ¿qué es exactamente lo que impide que esto suceda? –

+0

Puede que tengas razón, es confuso, así que realmente no puedo decirlo. –

0

operator==() es simplemente evaluar si f y b apuntan a la misma cosa, que en este caso son.

0

La mayoría de los compiladores diseñan el objeto de la clase padre al principio del objeto de la clase hija, por lo que las direcciones son las mismas, no hay sorpresas aquí.

0

Ha superpuesto esencialmente f y b en la misma ubicación de memoria (&bar). Entonces, en realidad, estoy confundido sobre cómo esperas que sean diferentes.

2

En general, la primera parte de una clase derivada es su elemento principal. Por lo tanto, un puntero a derivado y un puntero a base en el mismo objeto son a menudo iguales. Sin embargo, esto cambia con herencia múltiple. En el caso de MI, en términos generales, la primera pat de una clase derivada es parents en un orden posiblemente arbitrario (no sé y no importa para esto). Por lo tanto, si tiene un puntero a derivado, un puntero a base1 y un puntero a base2, con herencia multiplicada derivada de ambos, los tres punteros probablemente no sean todos iguales; dos podrían ser.

El vacío * no tiene que ser el mismo, pero generalmente lo será.

El reinterpret_cast a int es el mismo porque los valores de los punteros son los mismos.

+0

-1 '' static_cast' al valor void * 'no cambia de punta que está implícito en la respuesta –

+0

dos estamos mal. He solucionado mi error –

Cuestiones relacionadas