2012-03-30 25 views
5

Por ejemplo, tengo una jerarquía de clases (posiblemente, con todo tipo de herencia -, privado, público, múltiples herencia virtual pública, etc.):¿Cuándo puedo comparar punteros al mismo objeto en C++?

class A { 
    int a; 
public: 
    virtual ~A() {} 
}; 

class B: public A { int b; }; 
class C: public virtual B { int c; }; 
class E: public virtual B { int e; }; 
class F: public C, public E { int f; }; 

El uso de moldes que recibo punteros a cada sub objeto de la principal objeto "grande":

F * f = new F; 
E * e = f; 
C * c = f; 
B * b = f; 
A * a = f; 

Qué pares de estos punteros puedo comparar la igualdad (== operador) y por qué? ¿La comparación usará delta-logic o alguna otra técnica?

¿Cuáles son las situaciones posibles, cuando no puedo comparar punteros al mismo objeto complejo? ¿Qué tipo de objeto puede ser?

Espero que todos los punteros al mismo objeto sean siempre iguales.

+1

* ¿Por qué? * ¿desea compararlos ?, esa es la pregunta . – Jon

+3

Los punteros son simplemente direcciones. Si desea comparar todo, puede tratarse de objetos apuntados por los punteros. No puede comparar dos direcciones y decir si los objetos en esas ubicaciones son iguales. Bueno, err ... Puede hacerlo. ... pero eso está muy mal. –

+0

@Als: si hago 'std :: cout << (e == b) <<" "<< e <<" "<< b << std :: endl;', imprime '1 0x1aaa020 0x1aaa030' . Entonces las direcciones son diferentes, pero los punteros son iguales. Toda la pregunta es acerca de las reglas comunes de C++ de ese tipo de comparaciones. –

Respuesta

3

Puede comparar dos punteros, si un tipo de puntero es convertir implícitamente a la otra ; es decir, si ambos apuntan al mismo tipo, o uno apunta a una clase base de la otra. La conversión hará el ajuste necesario a la dirección de modo que, si ambos apuntan al mismo objeto, compararán igual.

En este caso, puede comparar cualquier par excepto c == e, ya que ninguno de C ni se deriva del otro. Para compararlos, tendrías que realizar un cross-cast o convertir ambos a su clase base común; ninguno de estos puede hacerse implícitamente.

Por cierto, no hay necesidad de dynamic_cast en su código, ya que está convirtiendo a punteros de clase base y que la conversión segura se puede hacer implícitamente.

3

Tienes que tener cuidado aquí. Por ejemplo, c y e son punteros a distintos aspectos de * f, y por lo tanto no son realmente el mismo objeto. Afortunadamente, el compilador le dará un error si intenta comparar c y e porque uno no se deriva del otro. Cualquier otra comparación en su ejemplo funcionará porque uno de los punteros se puede convertir trivialmente al tipo del otro.

class A { 
    int a; 
public: 
    virtual ~A() {} 
}; 

class B: public A { int b; }; 
class C: public virtual B { int c; }; 
class E: public virtual B { int e; }; 
class F: public C, public E { int f; }; 

{ 
    F * f = new F; 
    E * e = dynamic_cast<E*>(f); 
    C * c = dynamic_cast<C*>(f); 
    B * b = dynamic_cast<B*>(f); 
    A * a = dynamic_cast<A*>(f); 
    cerr << (a==b) << "\n"; // true 
    cerr << (a==c) << "\n"; // true 
    cerr << (a==e) << "\n"; // true 
    cerr << (a==f) << "\n"; // true 
    cerr << (b==c) << "\n"; // true 
    cerr << (b==e) << "\n"; // true 
    cerr << (b==f) << "\n"; // true 
    cerr << (c==e) << "\n"; // compile error 
    cerr << (c==f) << "\n"; // true 
    cerr << (e==f) << "\n"; // true 
} 
0

Solo puede comparar los punteros del mismo tipo. Sin embargo, no siempre se necesita un modelo explícito para hacerlo. En el caso sencillo:

B * pB = new B(); 
A * pA = pB; 

if (pA == pB) {} //pB is implicitly cast to an A * 

Al llegar a las clases más complejas, que tendrá que añadir explícita yesos por lo

F * pF = new F(); 
C * pC = dynamic_cast<C *>(pF) 
A * pA1 = dynamic_cast<A *>(pF); 
A * pA2 = dynamic_cast<A *>(pC); 

//should all be true 
if (pF == dynamic_cast<F *>(pA)) {} 
if (pA1 == dynamic_cast<A *>(pF)) {} 
if (pA1 == pA2) {} 
1

Generalmente, para asegurar que los dos punteros (posiblemente de tipo diffrent) apuntan al mismo objeto, utilice

dynamic_cast<void*>(pointer1) == dynamic_cast<void*>(pointer2) 

Por supuesto, ambos tipos de puntero deben ser polimórficos para proporcionar dynamic_cast correcta

Si el jerarquía de clases tiene una sola raíz (posiblemente virtual), es posible convertir ambos punteros en punteros a la clase raíz y luego comparar dos resultados (sin fundición dinámica)

+0

@Konrad: ¿Por qué no tiene sentido? Si downcasting para ambos punteros muestra la misma dirección, entonces apuntan al mismo objeto (y viceversa). Si los tipos de puntero no son intercambiables entre sí (o alguna clase de raíz), no sé otra manera de verificarlo excepto de dynamic_cast (aunque puede ser que no es exactamente la pregunta del OP ...) – user396672

+0

@Konrad: mi código verifica que tanto pointer1 como pointer2 están (hacia abajo) convertidos en la mayoría de las clases derivadas se refieren al mismo objeto (no pretendo que esto responda estrictamente a la pregunta del OP) – user396672

+0

Después de leer el estándar (provocado por su nueva pregunta) tomo todo espalda. No estaba al tanto (y bastante seguro de lo contrario) de que el estándar establecía disposiciones adicionales para (cv calificado) 'void *' en un 'dynamic_cast'. –

Cuestiones relacionadas