2010-01-26 8 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; 
} 

Je ne comprends pas pourquoi cette compile (peut-être quelqu'un peut bien vouloir fournir des explications détaillées? Est-il quelque chose lié au nom consultation?C++ modèle coulée avec les classes dérivées

BTW, sur Solaris, SunStudio12 il ne compile pas: 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

Ce modèle struct ci-dessus ne fait pas vraiment beaucoup, n'est-ce pas? – BenG

+0

@BennyG: Il a entendu parler de problèmes dans le quartier et a décidé de venir jeter un coup d'œil. –

+0

désolé, effacé – yurec

Répondre

13

std::pair a un modèle constructeur:

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

"Effets: Initialise membres des membres correspondants de l'argument, effectuer des conversions implicites selon le besoin." (C++ 03, 20.2.2/4)

La conversion d'un pointeur de classe dérivée d'un pointeur de classe de base est implicite.

+1

+1 pour une réponse courte et précise :-) –

+0

Je ne suis pas convaincu, make_pair est une fonction de modèle, qui déduit les types des arguments. Droite? – yurec

+2

Oui, et cela fait une paire 'std :: (B *, B *)'. Il utilise ensuite le constructeur ci-dessus pour construire une paire 'std :: (A *, A *)'. Relisez la réponse. – GManNickG

0

Puisque B est dérivé de A, le vecteur v contiendra des pointeurs vers les structures de classe de base de l'objet b. Par conséquent, vous pouvez accéder aux membres de A, à savoir

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

EDIT: Mon erreur, comme indiqué ci-dessous, vous pouvez toujours jeter aux pointeurs de type B puisque le vecteur est de pointeurs, pas des objets, donc pas tranchage d'objet a eu lieu.

Un appel, comme

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

ne compilera pas car les éléments du vecteur sont des pointeurs de classe de base et ne peuvent pas indiquer aux membres de la classe dérivée sans fonte, soit

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

Notez également que un cast dynamique, comme dans

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

ne compilera pas avec l'erreur suivante dans 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

Les membres de la classe B n'ont pas été perdus et le type dynamique des objets pointés est toujours B. Les membres de B sont toujours accessibles: 'static_cast (v [0] .first) -> b' (bien que dans dans ce cas, un 'dynamic_cast' serait probablement préférable). –

+0

@tmatth: Comme le dit James McNellis, vous pouvez toujours accéder aux membres de la classe dérivée via une distribution. Peut-être que vous songez à trancher des objets? Cela se produit uniquement en utilisant un vecteur d'objets ('A'), pas un vecteur de pointeurs (' A * '). Dans ce cas, oui, les membres de 'B' seront discrètement rejetés. –

+0

J'ai édité pour refléter vos commentaires, j'espère que cela éclaircit. – tmatth

Questions connexes