2010-01-28 4 views
8

J'écris du code impliquant l'héritage d'une classe de base de pointeur de comptage de ref; et quelques complexités de C++ ont surgi. Je l'ai réduit comme suit:Multi-héritage de pointeur C++

Supposons que j'ai:

class A{}; 
class B{}; 
class C: public A, public B {}; 

C c; 
C* pc = &c; 
B* pb = &c; 
A* pa = &c; 

// does pa point to a valid A object? 
// does pb point to a valid B object? 

// does pa == pb ? 

En outre, le fait:

// pc == (C*) pa ? 
// pc == (C*) pb ? 

Merci!

+2

que voulez-vous dire par ==? Évidemment, les adresses sont les mêmes. –

+9

Les adresses ne sont pas nécessairement les mêmes. –

+1

Dans une implémentation d'héritage multiple (virtuel) que j'ai vu, un certain décalage est ajouté à l'adresse de base de l'objet de la classe dérivée pour accéder aux attributs et méthodes de B. Cependant, cela n'est pas visible pour l'utilisateur. Par conséquent, dans votre programme, vous pouvez toujours voir que l'adresse de A, B et C sont les mêmes. – mukeshkumar

Répondre

7
  • Est-ce que pa indique un objet A valide?
  • pb pointe-t-il sur un objet B valide?

Oui, le C* est converti afin que pa et pb pointent vers les bonnes adresses.

  • fait pa == pb?

Non, généralement pas. Il ne peut pas y avoir un objet A et un objet B à la même adresse.

De plus, est-

  • pc == (C *) par an?
  • pc == (C *) pb?

Le casting convertit les pointeurs de retour à l'adresse de l'objet C, afin que les deux égalités sont vraies.

+1

'dynamic_cast' est inapproprié ici et le style C est correct (quoique de mauvaise forme). Selon §5.4/7, le cast de style C peut invoquer un static_cast' où "- un pointeur vers un objet de type de classe de base non virtuel, un lvalue de type de classe de base non virtuel, ou un membre pointerto de non Le type de classe de base virtuelle peut être explicitement converti en un pointeur, une référence ou un pointeur vers un membre d'un type de classe dérivé, respectivement. " – Potatoswatter

+0

Oui, vous avez raison, la distribution dynamique ne serait nécessaire que si le 'pa' serait casté en un' B * ', par exemple. – sth

+0

Dans ce cas, l'expression 'dynamic_cast' serait simplement une façon élégante de dire' NULL'. Un A * ne peut pas être un B *, donc il échouerait toujours. – Potatoswatter

1
pc == pa; 
pc == pb; 

Non défini, dépend de la structure de la classe.

pc == (C*) pa; 
pc == (C*) pb; 

Ceci est correct.

pa == pb; 

No.

-ils pointent vers des objets valides?

Yes 
2

C intègre un A et un B.

class C: public A, public B {}; 

est très similaire au code C

struct C { 
    A self_a; 
    B self_b; 
}; 

et (B*) &c; est équivalent à static_cast< B* >(&c) est similaire à &c.self_b si vous utilisiez C. droite

En général, vous ne pouvez pas compter sur des pointeurs à différents types étant interchangeables ou comparables.

0

Ce que vous obtenez est quelque chose comme ça en mémoire

---------- 
| A data | 
---------- 
| B data | 
---------- 
| C data | 
---------- 

Donc, si vous voulez que l'ensemble de l'objet C, vous aurez un pointeur au début de la mémoire. Si vous voulez seulement la partie A, vous obtenez la même adresse puisque c'est là que se trouvent les membres de données. Si vous voulez la partie "B" vous obtenez le début + sizeof (A) + sizeof (tout ce que le compilateur ajoute pour vtable). Ainsi, dans l'exemple, pc! = Pb (pourrait être pc! = Pa) mais pa n'est jamais égal à pb.

+1

Je ne suis pas d'accord avec 'pc! = Pb'. En tapant le code de la question dans DevStudio 2005, j'obtiens tous les pointeurs avec la même valeur. Et c'est probablement ce que la norme C++ dit devrait arriver, dans ce cas - pas de méthodes virtuelles et pas de membres de données. Le PO a posté une autre question où les classes de base ont des membres, de sorte que la réponse est différente, ce qui est plus ou moins la réponse. – Skizz

+0

@Skizz: ce que vous voyez s'appelle l'optimisation de la classe de base vide http://www.google.com/search?q=empty+base+class+optimization il est implémenté par tous les compilateurs modernes mais est loin d'être obligatoire. – Potatoswatter

+1

classe A {}; classe B {}; classe C: public A, public B {}; int main() { C c; C * pc (&c); A * pa (pc); B * pb (pc); printf ("C = 0x% 08X \ nB = 0x% 08X \ nA = 0x% 08X \ n", pc, pb, pa) ;} sortie VS2008 version validée C = B = 0x0018FEFF 0x0018FF00 A = 0x0018FEFF Si vous modifiez l'ordre dans lequel C hérite de A et B, vous obtiendrez des valeurs différentes pour A et B –

0

Item 28 Meaning of Pointer Comparison en C++ Common Knowledge: Essential Intermediate Programming) explique la clé du pointeur d'objet en C++:

En C++, un objet peut avoir plusieurs adresses valides, et la comparaison de pointeur n'est pas une question sur les adresses. C'est une question sur l'identité de l'objet.

Jetez un oeil sur le code:

class A{}; 
class B{}; 
class C: public A, public B {}; 

C c; 
C* pc = &c; 
B* pb = &c; 
A* pa = &c; 

class C aussi bien de ses class A et class B, donc class C est à la fois class A et class B. l'objet C c a 3 adresses valides: adresse pour class A, class B et class C. La mise en œuvre dépend du compilateur, de sorte que vous ne pouvez pas assumer la mise en page de mémoire de class C, et il peut comme ceci:

---------- <- pc (0x7ffe7d10e1e0) 
|  | 
---------- <- pa (0x7ffe7d10e1e4) 
| A data | 
---------- <- pb (0x7ffe7d10e1e8) 
| B data | 
---------- 
| C data | 
---------- 

Dans le cas ci-dessus, bien que la valeur d'adresse de pc, pa et pb ne sont pas identiques, ils se réfèrent tous au même objet (c), donc le compilateur doit s'assurer que pc compare égale à la fois pa et pb, soit pc == pa et pc == pb. Le compilateur effectue cette comparaison en ajustant la valeur de l'un des pointeurs comparés par le décalage approprié. Par exemple,

pc == pa 

est traduit:

pc ? ((uintptr_t)pc + 4 == (uintptr_t)pa) : (pa == 0) 

, entre autres, depuis A et B ont aucune relation d'héritage, nous ne pouvons pas comparer directement pa et pb.

Pour vos questions:

(1) does pa point to a valid A object? 
(2) does pb point to a valid B object? 
Yes, refer the above diagram. 

(3) pc == (C*) pa ? 
(4) pc == (C*) pb ? 
Yes, No need to add (C*). 

(5) does pa == pb ? 
No. We can't compare them.