C++ pointer multi-inheritance fun

后端 未结 5 1503
自闭症患者
自闭症患者 2020-11-30 09:02

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 h

相关标签:
5条回答
  • 2020-11-30 09:47

    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.

    0 讨论(0)
  • 2020-11-30 09:52

    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.
    
    0 讨论(0)
  • 2020-11-30 09:55
    • 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.

    0 讨论(0)
  • 2020-11-30 10:00
    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
    
    0 讨论(0)
  • 2020-11-30 10:00

    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.

    0 讨论(0)
提交回复
热议问题