CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Aug 2001
    Location
    Germany
    Posts
    1,384

    Casting b/w Base Derived Class

    Hi *!
    Lets say i have a base class & derived classes like
    PHP Code:
    class main {
      public:
      
    virtual void foo(){}
     };

    class 
    derive1  void foo(){}};
    class 
    derive2 : public main, public derive1 void foo(){}}; 
    Now if i do something like that

    PHP Code:
    DWORD ret = (DWORD)static_cast<main*>((derive2*)1) - // now ret = 0    O.K
    ret = (DWORD)static_cast<derive1*>((derive2*)1) - ;  // now ret = 4 WHY????????? & HOW?????? 
    What I dont understand is (it has to do something with virtual functions i think) But what exactly is it?????????
    and secondly why am i getting 4 just by casting as far i understand casting is a hint that the var that is being casted to be treated of a different type then it is now after the cast but doenst have anything to do with the value.
    Thanks for your time,
    Regards,
    Usman.

  2. #2
    Join Date
    Jun 2002
    Posts
    224
    I believe your problem is the pointer arithmetic not the virtual functions. Consider the following example
    Code:
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
      int* pi0 = (int*)0; // pointer to element 0 at address 0
      int* pi1 = (int*)1; // does not point to element 1; points to the byte at addres 1
      pi0++; // increments the pointer; not equivalent to (int*)1
      if ( pi0 == pi1 )
        cout << "never reached" << endl;
      else
        cout << "oops!" << endl;
      return 0;
    }
    I hope I correctly understood your problem.

    Regards,
    ZDF

    What is good is twice as good if it's simple.
    "Make it simple" is a complex task.

  3. #3
    Join Date
    Aug 2001
    Location
    Germany
    Posts
    1,384
    Thanks for the reply. I dont think it is pointer arithmatic coz I am casting 1 that I think is constant so I dont think its possible to change that value & in your case you did
    Code:
    pi0++;
    i.e a variable not a constant & what I posted in my post except of ret, there isn't any variable. Secondly If you take out the virtual keyword from the base class then the ret is equal to 1. Strange...
    Regards,
    Usman.

    P.S: I dont understand much whats happening in that line of code, So dont know how to explain it better Sorry for that.

  4. #4
    Join Date
    Jun 2002
    Posts
    224
    I do not understand. You expect ret to be zero in both cases?
    ZDF

    What is good is twice as good if it's simple.
    "Make it simple" is a complex task.

  5. #5
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125
    The problem is one of the root issues with why multiple inheritance is complicated (many say bad...)

    A Derived2 object has multiple base addresses...

    It has a Main1 object that resides at the starting address of the Derived2 object. If also has a Derived1 object that begins at:

    Derived2(base) + sizeof(Main1)

    Since main 1 has a vtbl, it has a size of 4 (for this compiler at least). If it had NO virtual functions, but had member variables, the diffeerence between your two results would be the net size of the member variables.

    Worse consider the following code (which does not involve casts to DWORD)

    Derived2 realObject
    Main1 *m = &realObject;
    Derive1 *d = &realObject;

    if (m == d)
    cout << "Same Object";
    else
    cout << "Different Object";

    the above code WILL print out DIFFERENT OBJECT!!!!!!


    See Item #43 in Scott Meyers "Effective C++" for in depth information.

  6. #6
    Join Date
    Oct 2002
    Location
    Tel Aviv
    Posts
    149
    Hi,
    I compiled assembly code of this example. Looks like is supports TheCPUWizard's reply.

    PHP Code:
    // option 1
    class A
    {
        
    virtual void func(){}
    };

    class 
    B
    {
    };

    class 
    : public A, public B
    {
    };

    int main(int argccharargv[])
    {
        
    DWORD ret = (DWORD)(A*)(C*)1;
        
    ret = (DWORD)(B*)((C*)1);
        return 
    ret;
    }

    // assebly
    24   :     DWORD ret = (DWORD)(A*)(C*)1;

        
    mov    DWORD PTR _ret$[ebp], 1

    25   :     ret = (DWORD)(B*)((C*)1);

        
    mov    eax1
        test    eax
    eax
        je    SHORT $L17059
        mov    ecx
    // look at this line
        
    add    ecx1
        mov    DWORD PTR 
    -8+[ebp], ecx
        jmp    SHORT $L17060
    $L17059
    :
        
    mov    DWORD PTR -8+[ebp], 0
    $L17060
    :
        
    mov    edxDWORD PTR -8+[ebp]
        
    mov    DWORD PTR _ret$[ebp], edx

    // option 2 - add member to class A
    class A
    {
        
    virtual void func(){}
        
    int a;
    };

    class 
    B
    {
    };

    class 
    : public A, public B
    {
    };

    int main(int argccharargv[])
    {
        
    DWORD ret = (DWORD)(A*)(C*)1;
        
    ret = (DWORD)(B*)((C*)1);
        return 
    ret;
    }

    // the assemly
    25   :     DWORD ret = (DWORD)(A*)(C*)1;

        
    mov    DWORD PTR _ret$[ebp], 1

    26   :     ret = (DWORD)(B*)((C*)1);

        
    mov    eax1
        test    eax
    eax
        je    SHORT $L17060
        mov    ecx
    // look at this line
        
    add    ecx1
        mov    DWORD PTR 
    -8+[ebp], ecx
        jmp    SHORT $L17061
    $L17060
    :
        
    mov    DWORD PTR -8+[ebp], 0
    $L17061
    :
        
    mov    edxDWORD PTR -8+[ebp]
        
    mov    DWORD PTR _ret$[ebp], edx 

    regards
    omri

  7. #7
    Join Date
    Jun 2002
    Posts
    224
    Hi Usman,

    As TheCPUWizard pointed out it is not possible to get the same value for ret. I do not see any practical use for the code you posted. So, is there any practical use for the code you posted or is just curiosity?

    Regards,
    ZDF

    What is good is twice as good if it's simple.
    "Make it simple" is a complex task.

  8. #8
    Join Date
    Aug 2001
    Location
    Germany
    Posts
    1,384
    Thank you all for your reply!
    What i understand now correct me if I am wrong.
    Code:
    class main {
    public:
    virtual	void foo(){}
    }
    
    };
    class derive1  { void foo(){}
    };
    class derive2 : public main, public derive1 { void foo(){}};
    PHP Code:

    now the Object 
    for derive2 should looklike
        Address 0 
    :  main Obj Starts vtable
        Address 4 
    :  derive 1 Starts // No var & no virtual function so I guess no vtable
        
    Address 4 :  derive 2 starts // Is correct that both starts at the same address??????? d1 & d2 

    So if i now cast derive2 pointer to main lets say it's value is 4. So it should be reduced by 4 to point to main.
    I think i am missing something here. coz the answer is not that. Actually there's a macro in ATL for that sortof thing, I didnt understand why & whats happening when I saw that, thats why I posted it here.
    Thanks for your time,
    Regards,
    Usman.
    P.S: Sorry I am not good at assembly :(
    Last edited by usman999_1; December 3rd, 2002 at 06:47 AM.

  9. #9
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125
    Close but not quite. Remember Derived2 CONTAINS Main and Derived1. Therefore

    Address 0 : Derived2 and Main
    Address n : Derived1 (n=4 because Main has Vtable and no data)
    Address m: Derived2 Members (m=-n+sizeof(Derived1)) [0 in your case]

    -------------------------

    Please note that if you changed your class to:

    Derived2 : public Derived1, public main

    This would change to

    Address 0: Derived2 and Derived1 and Main

    This is because Derived1 has no size.

    ----------------------

    Multiple inheritance causes many issues such as this. Even neglecting the "diamond" problem, multiple inheritance (except for interfaces) is usually more trouble than it is worth (consider using aggregation instead).

    To see a workable method os supporting multiple inheritance look at the COM function QueryInterface. This is ONE method that is commonly used for casting between different base classes.

    Hope this helps.

  10. #10
    Join Date
    Aug 2001
    Location
    Germany
    Posts
    1,384
    One more question .
    I think every derived class has a sub object/s of the super/base class/es & that sub object starts before the derived class object starts. So if I instentiate the derive2 class it will hav two sub-objects main & derive1 and the derived derive2 class object starts at the end of these sub objects. So at address 0, the main object should start and when that ends derive1 should start then the last class which is instaniated.
    But in your reply d2 & m start at 0 should it be only main at 0 then after main derive1 (which is 0) so after that derive 2 at Address 5.
    Thanks for your time.
    Regards,
    Usman.
    I am not very much into COM & stuff, but just wanted to know bit more bout the C++ object Model.

  11. #11
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125
    The reason "d2" STARTS at 0 (relative to everything else) is that the definition of "d2" CONTAINS "m" and "d1".

    You are correct that unique data members added by "d2" start after the memory taken by "m" and "d1", but the COMPLETE "d2" object also consists of all of the members of "m" and "d1".

    Hope this clears thing up regarding class layouts.

    Regarding the order of calls. Technically the constructor of "d2" if the first thing (and only thing) called by the creator of the d2 object. Hidden from view (before the opening brace of the constructor) are calls to "m" and "d1". Therefore if you put breakpoints on the first line of the constructor of each class, it LOOKS like the order of call is "m", "d1", "d2". On the other hand if you put the breakpoint on the method definition itself (e.g. "d1:1()") you will see the true order.

  12. #12
    Join Date
    Aug 2001
    Location
    Germany
    Posts
    1,384
    Thanks a lot! I got it .
    Regards,
    Usman.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured