12

I'm writing some code involving inheritance from a basic ref-counting pointer class; and some intricacies of C++ popped up. I've reduced it as follows:

Suppose I have:

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 ?

Furthermore, does:

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

Thanks!

5
  • 2
    what do you mean by ==? Obviously, the addresses are the same. Commented Jan 28, 2010 at 19:04
  • 9
    The addresses are not necesarrily the same. Commented Jan 28, 2010 at 19:09
  • 1
    In one implementation of multiple inheritance (virtual) which i have seen, some offset is added to base address of derived class's object to access the attributes and methods of B. However this is not visible to the user as compiler manipulates it internally. Hence in your program you may still see that the address of A, B and C are same. Commented Jan 28, 2010 at 19:10
  • @hype: The operative word here being "may." Commented Jan 28, 2010 at 19:25
  • @Dave Bacher This isn't true all the time. I personally had a segfault a while back while trying to dereference a pointer of one that pointed to an object, but the pointer had a different type than what the function expected. However, the object inherited from both types. It may work, but it isn't safe. Commented Jan 28, 2010 at 19:43

5 Answers 5

10
  • does pa point to a valid A object?
  • does pb point to a valid B object?

Yes, the C* gets converted so that pa and pb point to the correct addresses.

  • does pa == pb ?

No, usually not. There can't be an A object and a B object at the same address.

Furthermore, does

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

The cast converts the pointers back to the address of the C object, so both equalities are true.

Sign up to request clarification or add additional context in comments.

14 Comments

dynamic_cast is inappropriate here and C-style is correct (albeit bad form). According to §5.4/7, C-style casting may invoke a static_cast where "— a pointer to an object of non-virtual base class type, an lvalue of non-virtual base class type, or a pointerto member of non-virtual base class type may be explicitly converted to a pointer, a reference, or a pointer to member of a derived class type, respectively."
Yeah, you are right, the dynamic cast would only be needed if the pa would be casted to a B*, for example.
In that case, the dynamic_cast expression would just be a fancy way to say NULL. An A* can't be a B* so it would always fail.
@Potatoswatter: No, that would work, since pa really is a C*, and a C* can be converted to a B*. But to figure that out a dynamic_cast is needed.
@Skizz: Assume by default that the base classes aren't empty. A newbie doesn't need to be misled by a technicality about his example. pa == pb is UNDEFINED, the answer isn't a definite yes anyway.
|
5

Item 28 Meaning of Pointer Comparison in C++ Common Knowledge: Essential Intermediate Programming) explains the key of object pointer in C++:

In C++, an object can have multiple, valid addresses, and pointer comparison is not a question about addresses. It's a question about object identity.

Take a look at the code:

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

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

class C derives from both class A and class B, so class C is both class A and class B. the object C c has 3 valid addresses: address for class A, class B and class C. The implementation depends on compiler, so you can't assume the memory layout of class C, and it may like this:

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

In above case, although the address value of pc, pa and pb aren't same, they all refer to the same object (c), so the compiler must ensure that pc compares equal to both pa and pb, i.e., pc == pa and pc == pb. The compiler accomplishes this comparison by adjusting the value of one of the pointers being compared by the appropriate offset. E.g.,

pc == pa

is translated to:

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

Among other things, since A and B have no inheritance relationship, we can't compare pa and pb directly.

For your 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.

1 Comment

(6) does (C*)pa == (C*)pb ?
2

C embeds an A and a B.

class C: public A, public B {};

is very similar to the C code

struct C {
    A self_a;
    B self_b;
};

and (B*) &c; is equivalent to static_cast< B* >( &c ) is similar to &c.self_b if you were using straight C.

In general, you can't rely on pointers to different types being interchangeable or comparable.

Comments

1
pc == pa;
pc == pb;

Not defined, depends on class structure.

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

Thats ok.

pa == pb;

No.

Do they point to valid objects?

Yes

Comments

0

What you get is something like this in memory

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

So if you want the entire C object you'll get a pointer to the beginning of the memory. If you want only the A "part", you get the same address since that's where the data members are located. If you want the B "part" you get the beginning + sizeof(A) + sizeof(whatever the compiler adds for vtable). Thus, in the example, pc != pb (could be pc != pa) but pa is never equal to pb.

3 Comments

I beg to differ on the pc != pb. Typing the question's code into DevStudio 2005, I get all pointers with the same value. And that's probably what the C++ standard says should happen, in this case - no virtual methods and no data members. The OP has posted another question where the base classes do have members, so that has a different answer, which is this answer more or less.
@Skizz: what you're seeing is called the Empty Base Class optimization google.com/search?q=empty+base+class+optimization it's implemented by all modern compilers but is far from being required.
class A{}; class B{}; class 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); } output from VS2008 Release build C=0x0018FEFF B=0x0018FF00 A=0x0018FEFF If you change the order in which C inherits from A and B, you'll get different values for A and B

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.