2010-03-21 6 views
1

Si B est la sous-classe A.Coulée de pointeurs vers des objets

Et je en main():

B** b = new B*[10]; 
... // some algorithm that does b[i] = new B(..); 

J'ai un tableau de pointeurs vers des objets B.

, j'ai une fonction:

void f(A** foo); 

Si dans le principal, je fais: f(b); je reçois un avertissement, mais il est évident que je fais: f((A**)b);, je ne. Le (A**) est un peu méchant. Je me demandais s'il y avait une manière plus élégante en C++ qu'au moins faire la vérification de type comme dynamic_cast. Je veux foo pour trier (seulement en utilisant des swaps) des tableaux d'objets de type A ou sous-classe .. donc faites un algorithme de tri générique. J'espère que vous comprenez mieux mon problème.

+0

Êtes-vous autorisé à utiliser des vecteurs? – GManNickG

+0

non, je ne suis pas autorisé – ritmbo

Répondre

2

A** et B** sont deux types totalement différents. Tout simplement parce qu'il y a une conversion implicite de B* à A* ne signifie pas que la même conversion existe de B** à A** Voir cette FAQ Converting Derived* → Base* works OK; why doesn't Derived** → Base** work? pour plus de détails.

+0

Merci, mais je ne peux pas résoudre mon problème. Je veux A avoir une fonction qui trie les tableaux de type A et toutes les sous-classes de A. Quelle est la bonne façon de le faire? – ritmbo

+0

@ritmbo: est-ce quelque chose de similaire à ce que vous voulez faire: http://codepad.org/DlErsYLj – Naveen

+0

Je ne peux pas utiliser le vecteur – ritmbo

1

Le cas est incorrect. Supposons que la fonction est (parfaitement légitime):

void f(A** foo) 
{ 
    foo[0] = new A(); 
} 

maintenant si vous avez passé un B** instead, le premier pointeur (que le compilateur est certain est un B*) est devenu tout à coup un A* - type terrible violation, Hard- accident probable bientôt.

A** - pas de const en vue, veuillez noter! - désigne un pointeur mutable pointant vers pointeurs modifiables, ce qui explique pourquoi la définition de l'un de ces pointeurs sur un nouveau pointeur sur A est parfaitement OK. Mais vous ne pouvez pas le faire si vous avez réellement un B** - ces pointeurs doit toujours à B (ou sous-classe de celui-ci), pas-A, un superclasse de B. Oui, c'est la covariance contre la contre-variance encore une fois - sous la mutabilité (pas de const en vue), c'est vraiment un champ de mines. Pourquoi ne pas coller dans tous les const vous pouvez éventuellement vous permettre? Cela indiquera également quels cas ont du sens dans quelles circonstances!

+0

Mon problème est que le f, seulement échanger des choses du tableau. Donc, si j'utilise const, alors je ne peux pas faire ce que je veux faire. – ritmbo

2

Il y a une raison pour laquelle vous recevez un avertissement ou une erreur si vous essayez de lancer implicitement un B** vers un A**: ce n'est pas prudent de le faire. En vous référant au tableau A**, vous pouvez placer des pointeurs sur les objets A à l'intérieur. Pour un tableau de B*, cela est faux et, par conséquent, la distribution est dangereuse.

Peut-être f serait mieux une fonction de modèle:

template<typename T> 
void f(T **array) { 
    ... 
} 
+0

En outre, même si C++ ne vous autorise pas (encore) à limiter explicitement T aux sous-types de A, lorsque vous transmettez les paramètres réels T * à une fonction de comparaison acceptant les paramètres formels A *, le compilateur appliquera T() publiquement) de A. –

+0

@BenVoigt: vous pouvez utiliser un cast implicite dans la fonction sans appeler une autre fonction ... comme: 'Base * elem = array [i];' qui ne sera pas compilé si le tableau n'est pas dérivé de Base – smerlin

+0

@ smerlin: Oui, la logique de comparaison pourrait être à l'intérieur de la fonction de tri. Mais le mot-clé inline est si efficace, et vous obtenez tellement de réutilisation supplémentaire en séparant la logique de tri de la commande, que l'utilisation d'une fonction de comparaison est une bonne habitude et certainement à encourager lors de l'enseignement de la programmation. –

0

Si B est une sous-classe de A alors vous pouvez toujours trier une liste de pointeurs vers des objets de type B même si le type du tableau est " tableau de pointeurs à A ".

E.g.

A** ptrToBs = new A*[10]; 

ptrToBs[0] = &b01; // ... or new B 
ptrToBs[1] = &b02; 

// ... 

ptrToBs[9] = &b10; 

f(ptrToBs); 

Cependant, ce que vous dites que vous voulez est un algorithme générique pour échanger des objets, pas des pointeurs en fonction de la valeur des objets pointés. Dans ce cas, il vaut mieux avoir un modèle de fonction.

template< class T > 
void f(T* t) 
{ 
    // ... 
} 

De cette façon, vous pouvez trier un tableau de A ou et tableau de B sans avoir à un tableau de pointeur exactement le bon type; vous pouvez simplement trier un tableau d'objets A ou B ou toute autre chose à condition que le type d'objets que vous triez supporte les opérations que vous utilisez dans votre algorithme de tri.

Typiquement, vous voudriez passer la taille du tableau ou un pointeur à la fin du tableau pour que l'algorithme n'ait pas à assumer la taille du tableau.

template< class T > void f(T* arr, std::size_t size); 

ou

template< class T > void f(T* first, T* last); 
Questions connexes