Saturday, December 06, 2003

Re: Type Casting

I am not sure how each language/platform implements type casting. I assume that it is similar in all. I dunno why they would have differing implementations since it is essentially the same concept.

This is what I think goes on. I am not sure about this at all. Maybe Dinesh/Hrishi can add/correct stuff about this.

First, just to be clear, there is a difference between a pointer/reference and an actual object...

A pointer/reference is always of fixed size (4 bytes on 32 bit machines) and has a type associated with it. Once that type is associated with a pointer/reference it can NEVER be changed. These pointers/references are located on the stack and point to instances of classes (objects). They allow you to access and play with actual objects.

Class instances or objects can be located both on the stack and heap in C++/C# and only on the heap in Java. They vary in size based on the class "blueprint". And it's size grows, if it is part of a class hierarchy (inheritance). Uness you have a pointer/reference pointing to them, you CAN'T do anything to them.

I guess you can think of the pointer/reference as providing a "view" of an object.


// C++

class A
{
public:
    int m_dataA;

    void functionA() { std::cout << "functionA"; }
};


It just contains one data member. So when you create an object of this class, it is just this one member that is loaded on the stack or heap.


// Heap
-----------------
| int m_dataA
-----------------


Now to do something to it, you need a pointer/reference.


A* p = new A;


Through p, you have a "view" of this object. That view is limited to the size of A. As in, p has access to everything from 0 to sizeof(A), if you consider 0 to be the address of where this objected is created. In this case p can view everything. Generally, the size of an object is just the sum of the size of each data member. In this case, sizeof(A) would most probably be equal to sizeof(int). Functions are NOT part of the class.


// Stack    // Heap
p------>    ----------------- address: 0
            | int m_dataA
            ----------------- address: 3


Now consider if the class is part of a hierarchy.


// C++

class B : public class A
{
public:
    int m_dataB;

    void functionB() { std::cout << "funtionB"; }
};


Now if we have an object of class B, the heap will look like...


// Heap
-----------------
| int m_dataA
| int m_dataB
-----------------


And if we have a pointer/reference of type B, we can access EVERYTHING in the object, because sizeof(B) includes everything.


B* p = new B;

// Stack    // Heap
p------>    ----------------- address: 0
            | int m_dataA
            | int m_dataB
            ----------------- addresss: 7


But what happens if we have an A pointer/reference to this object? Going back to the view analogy... it will only allow you to see things A can see, which is sizeof(A)


A* p = new B;

// Stack    // Heap
p------>    ----------------- address: 0
            | int m_dataA
            | int m_dataB
            ----------------- address: 7


Here, m_dataB exists and is part of the object on the heap, but it just cannot be seen using a A pointer/reference.

So finally, answering your question, casting just provides a view to an object. In this case, to see ALL of B, you will need to cast it...


B* p2 = (B) p;


This will grant access to everything in B.

In your example, the collection accepts Objects, which is the root class of ALL objects in java/c#. So when you pass in Strings, String objects are created on the heap, but they are viewed through Object references. When you get back these Strings from the collection using get(index), you have to cast them to Strings to be able to view everything.

Regarding the v-tables. Again, I'm not sure how they are implemented in java and c#. I would assume that they do it the same way as C++.

No comments: