2

I have a doubt: I can declare a pointer to a class member function

void (*MyClass::myFunc)(void);

and I can declare a pointer to a class member variable

int (MyClass::*var);

My question is: how is an object (composed by member functions and member variables) structured in memory (asm-level) ?

I'm not sure because, except for polymorphism and runtime virtual functions, I can declare a pointer to a member function even without an object and this implies that the code functions are shared among multiple classes (although they require a *this pointer to work properly)

But what about the variables? How come I can declare a pointer to a member variable even without an object instance? Of course I need one to use it, but the fact that I can declare a pointer without an object makes me think a class object in memory represents its variables with pointers to other memory regions.

I'm not sure if I explained properly my doubt, if not just let me know and I'll try to explain it better

Johnny Pauling
  • 12,701
  • 18
  • 65
  • 108

1 Answers1

4

Classes are stored in memory quite simply - almost the same way as structures. If you inspect the memory in the place, where the class instance is stored, you'll notice, that its fields are simply packed one after another.

There's a difference though, if your class have virtual methods. In such case the first thing stored in a class instance is a pointer to a virtual method table, which allows virtual methods to work properly. You can read more about this on the Internet, that's a little more advanced topic. Luckily, you don't have to worry about that, compiler does it all for you (I mean, handling VMT, not worrying).

Let's go to the methods. When you see:

void MyClass::myFunc(int i, int j) { }

Actually the compiler converts it into something like:

void myFunc(MyClass * this, int i, int j) { }

And when you call:

myClassInstance->myFunc(1, 2);

Compiler generates the following code:

myFunc(myClassInstance, 1, 2);

Please keep in mind, that this is a simplification - sometimes it's a little more complicated than this (especially when we discuss the virtual method calls), but it shows more or less, how classes are handled by the compiler. If you use some low-level debugger such as WinDbg, you can inspect parameters of the method call and you'll see, that the first parameter is usually a pointer to class instance you called the method on.

Now, all classes of the same type share their methods' binaries (compiled code). Therefore there is no point in making copy of them for each class instance, so there is only one copy held in the memory and all instances use it. It should be clear now, why can you get the pointer to method even if you have no instance of the class.

However, if you want to call the method kept in a variable, you always have to provide a class instance, which can be passed by the hidden "this" parameter.


Edit: In response to comments

You can read more about pointer members in another SO question. I guess, that pointer to member stores the difference between the beginning of classes instance and the specified field. When you try to retrieve the value of a field using the pointer-to-member, compiler locates the beginning of classes instance and move by amount of bytes stored in pointer-to-member to reach the specified field.

Each class instance has its own copy of non-static fields - otherwise they wouldn't be much of a use for us.

Notice, that similarly to pointers to methods, you cannot use pointer to member directly, you again have to provide a class instance.

A proof of what I say would be in order, so here it is:

class C
{
public:
    int a;
    int b;
};

// Disassembly of fragment of code:

    int C::*pointerToA = &C::a;
00DB438C  mov         dword ptr [pointerToA],0  
    int C::*pointerToB = &C::b;
00DB4393  mov         dword ptr [pointerToB],4  

Can you see the values stored in pointerToA and pointerToB? Field a is distant by 0 bytes from the beginning of classes instance, so value 0 is stored in pointerToA. On the other hand, field b is stored after the field a, which is 4 bytes long, so value 4 is stored in pointerToB.

Community
  • 1
  • 1
Spook
  • 25,318
  • 18
  • 90
  • 167