2

So i know that an int * knows to dereference 4 bytes and a bool * knows to dereference 1.

Now if there was a class :

Class rectangle {
     Int l;
     Int w;
 };

Now does a rectangle* know to dereference 8 bytes ?

And if so, now suppose that there is a parent class Shape and classes rectangle and circle that inherit from shapes.

Class circle {
     Int r;
 };

Now if i make a Shape* pointing to a rectangle. How will it know to dereference 8 bytes and not 4 ( of circle).

hussamh10
  • 129
  • 9
  • 3
    The compiler knows the type you're using, and so also knows its size. See sizeof() – James Jun 17 '16 at 20:01
  • 2
    "Now if i make a Shape* pointing to a rectangle. How will it know to dereference 8 bytes and not 4 ( of circle)." - it won't. Try that, and you'll get object slicing problems. – user2357112 Jun 17 '16 at 20:02
  • BTW, your post is not showing any inheritance. – Thomas Matthews Jun 17 '16 at 20:05
  • dereferencing literally means to acquire the data at some address, the size or even type of data at that address is largely irrelevant. consider this case: a pointer A points to B, the pointer B points to C -- i don't actually care what they are, but this statement will resolve the data at address C `**A` because A is dereferenced once (acquiring the data at B, which is another address because it too is a pointer) and then again to acquire the data at C. if you then call some method on that `(**A).someMethod()` 'someMethod' has a byte offset that seeks from the pointer location – kirinthos Jun 17 '16 at 20:38

6 Answers6

5

For an object, the compiler knows the type and thus knows the size.

For a pointer, the compiler still knows the type and thus knows the size.

But if the pointer is to a subclass... It's still going to use the base class! The compiler doesn't have the slightest idea because what's in that memory won't get there until runtime. There could be 1 shape, there could be a billion shapes. They could be subclasses of shapes, some circles and some rectangles, and some MöbiusParallelograms. The best it can do is dereference a shape and slice away all non-shape behaviour.

Watch what happens here:

#include <iostream>

class shape
{

};
class rectangle:public shape {
     int l;
     int w;
 };
class circle:public shape {
     int r;
 };

int main()
{
    shape s;
    rectangle r;
    circle c;

    shape* sp;

    std::cout << "Size of shape: " << sizeof(s) << std::endl;
    std::cout << "Size of rectangle: " << sizeof(r) << std::endl;
    std::cout << "Size of circle: " << sizeof(c) << std::endl;

    sp = &s;
    std::cout << "Size of dereferenced shape pointer pointing to shape: " << sizeof(*sp) << std::endl;

    sp = &r;
    std::cout << "Size of dereferenced shape pointer pointing to rectangle: " << sizeof(*sp) << std::endl;

    sp = &c;
    std::cout << "Size of dereferenced shape pointer pointing to circle: " << sizeof(*sp) << std::endl;
}

Example output:

Size of shape: 1
Size of rectangle: 8
Size of circle: 4
Size of dereferenced shape pointer pointing to shape: 1
Size of dereferenced shape pointer pointing to rectangle: 1
Size of dereferenced shape pointer pointing to circle: 1

shapes! All of them, shapes! All of their individuality has been stripped away.

user4581301
  • 33,082
  • 7
  • 33
  • 54
2

Now if i make a Shape* pointing to a rectangle. How will it know to dereference 8 bytes and not 4 ( of circle).

The compiler won't know how to do that. If you have a Shape* it only knows about Shape, not anything about the derived classes.

A well known related phenomenon is object slicing. When you assign a derived class object to a base class object, you lose the derived class information in the base class object.

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

Every pointer has a type; or the type of the object it is pointing to.

The compiler uses this type information to validate the referenced member (function or data member). From the type, the compiler can figure out how much memory to derference.

Edit 1:
When using pointers to a base class, the compiler only knows about the base class items (members and functions). So dereferencing a base class pointer gives access to items in the base class.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
1

There's a reason why you can only access known members of a class in an hierarchy.

struct Shape {};

struct Rectangle : public Shape
{
   int w, h;
};

struct Circle : public Shape
{
   int r;
};

int main()
{
   Circle c;

   Shape* s = &c;

   cout << s->r << '\n'; // compile error, no r in type Shape

   // the following is "OK", though in practice downcasting like
   // this is something we should avoid when possible
   cout << static_cast<Circle&>(*s)->r << '\n';  
}
Chad
  • 18,706
  • 4
  • 46
  • 63
1

Now does a rectangle* know to dereference 8 bytes ?

compiler has access to complete type of rectangle, this means it knows its layout can calculate alignment of variables. This is needed to calculate sizeof(rectangle) and this value is used when you for example have a pointer pRectanle and you increament it with pRectangle+1.

If you forward declare your rectangle class then compiler has no access to complete type and will generate a compilation error, if you use any language feature which requires complete type (ie. dereferencing pointer, inheriting from class, ...)

Now if i make a Shape* pointing to a rectangle. How will it know to dereference 8 bytes and not 4 ( of circle).

I am not sure if I understand, for example: in here Shape* pS = pRectangle;, pS is of static type Shape* so when you increament this pointer or dereference then compiler sees only static type Shape and its size is used. Only when you call a virtual method using pS (if it has one) then dynamic type will be used. Otherwise pS+1 will cause pS pt be incremented by sizeof(Shape), which is not what you want if pS points to some array.

marcinj
  • 48,511
  • 9
  • 79
  • 100
1

The compiler does not need to know anything about the size of the object it is dereferencing. All dereferencing does is load the value at the address contained in our pointer.

When refers to a member of a struct or class with the dot (.) operator, the compiler fetches the value at the designated offset from the beginning of the struct or class.

When one uses the arrow (->) operator, the compiler fetches the address and returns the offset to the element requested.

When one increments a pointer, the compiler adds the sizeof the object to the pointer value in memory, since the array of objects is contiguous, we are now pointing to the next object.

In C++, the element of the base classes are stored at before the data of the derived class, so downcasting or upcasting does not affect the pointer value.

In the case of mulitple inheritance, casting to a base class makes the compiler return the offset of the base class object in the derived class. This is why static_cast and reinterpret_cast may return different values.

doron
  • 27,972
  • 12
  • 65
  • 103