2010-01-26 13 views
5
#include <vector> 

struct A {int a;}; 
struct B : public A {char b;}; 

int main() 
{ 
    B b; 
    typedef std::pair<A*, A*> MyPair; 
    std::vector<MyPair> v; 
    v.push_back(std::make_pair(&b, &b)); //compiler error should be here(pair<B*,B*>) 
    return 0; 
} 

No entiendo por qué este compila (tal vez alguien amablemente puede proporcionar una explicación detallada? ¿Es algo relacionado con el nombre de consulta?C++ plantilla de fundición con las clases derivadas

Por cierto, en Solaris, SunStudio12 se no se compila: error : formal argument x of type const std::pair<A*, A*> & in call to std::vector<std::pair<A*,A*> >::push_back(const std::pair<A*, A*> &) is being passed std::pair<B*, B*>

+4

Esa plantilla de estructura anterior no está realmente haciendo mucho, ¿verdad? – BenG

+0

@BennyG: Se enteró de algunos problemas en el vecindario y decidió venir a echar un vistazo. –

+0

lo siento, lo borré – yurec

Respuesta

13

std::pair tiene una plantilla constructor:

template<class U, class V> pair(const pair<U, V> &p); 

"Efectos: Inicializa miembros de los miembros correspondientes del argumento, realizando conversiones implícitas según sea necesario." (C++ 03, 20.2.2/4)

La conversión de un puntero clase derivada a un puntero clase base está implícito

+1

+1 para respuestas cortas y precisas :-) –

+0

No estoy convencido, make_pair es una función de plantilla, que deduce tipos de argumentos. ¿Derecha? – yurec

+2

Sí, y hace un 'std :: pair (B *, B *)'. A continuación, utiliza el constructor anterior para construir un 'std :: pair (A *, A *)' fuera de él. – GManNickG

0

Como B se deriva de A, el vector v contendrá punteros a las estructuras de clase base del objeto b. Por lo tanto, se puede acceder a los miembros de A, es decir

std::cout << v[0].first->a; 

EDIT: Mi error, como se señala más adelante, todavía puede lanzar a los punteros de tipo B ya que el vector es de punteros, no objetos, por lo que hay rebanar objetos ha ocurrido.

Una llamada tales como

std::cout << v[0].first->b; 

no se compilará desde los elementos en el vector son punteros clase base y no pueden apuntar a miembros de la clase derivados sin una conversión, es decir,

std::cout << static_cast<B*>(v[0].first)->b; 

Observe también que un molde dinámico, como en

std::cout << dynamic_cast<B*>(v[0].first)->b; 

no se compilará con el siguiente error en gcc:

cast.cpp:14: error: cannot dynamic_cast ‘v.std::vector<_Tp, _Alloc>::operator[] [with _Tp = std::pair<A*, A*>, _Alloc = std::allocator<std::pair<A*, A*> >](0u)->std::pair<A*, A*>::first’ (of type struct A*’) to type struct B*’ (source type is not polymorphic) 
+2

Los miembros de la clase B no se han perdido, y el tipo dinámico de los objetos señalados sigue siendo B. Se puede acceder a los miembros de B: 'static_cast (v [0] .first) -> b' (aunque en este caso, un 'dynamic_cast' probablemente sería preferible). –

+0

@tmatth: como dice James McNellis, todavía puedes acceder a los miembros derivados de la clase a través de un elenco. ¿Tal vez estás pensando en rebanar objetos? Eso ocurre solo cuando se usa un vector de objetos ('A'), no un vector de punteros (' A * '). En ese caso, sí, los miembros de 'B' serán descartados silenciosamente. –

+0

he editado para reflejar sus comentarios, espero que esto lo aclare. – tmatth

Cuestiones relacionadas