Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are classes implemented internally in C++? [closed]

Tags:

c++

class

I tried googling it, but didn't find any result. Is the implementation similar to the class hack in C using struct of function pointers and data? Or is it implemented in some another form?

like image 884
cbinder Avatar asked Nov 24 '15 10:11

cbinder


Video Answer


2 Answers

I have not written any c++ compilers, but the structure of a class should contain:

  • base class(es) data part (containing all data for base classes of the class)
  • class instance data part (containing all data for an instance of the class)
  • virtual table pointer (if the class or it's bases have at least one virtual function)

Note: non-virtual functions are referenced statically, so they should not be bound to a class instance directly.

That said, each compiler probably implements this a bit differently.

TLDR: essentially yes, the implementation has to be similar to the class hack (but this should be transparent/irrelevant for developers).

Edit:

This post is mostly speculation, based on years of debugging with visual studio (very subjective), backed with some experience years ago, maintaining a project that had the class hack supporting inheritance, implemented in C (such experience is very subjective as well).

For an example, in Visual Studio 6, you could see that the virtual function table was allocated before the c++ implementation-specific data. That is, a class looked like this:

[vtbl][data]
^1    ^2

so if this was for (for example) struct X { virtual ~X(); int i; }, then writing:

X a;
X *p = &a;

would create something similar to this:

[ptr + 1] -> any other virtual functions
[ptr + 0] -> X::~X
^x

[^x][data]
^1  ^2
    ^p = ^2;

with ^1 being where the operating system would allocate memory (and the vtbl would be filled in within the implementation of new), then the offset to user data (vtbl + sizeof (vtbl)) would be returned to the client code, as the address of the class. I don't know if this is still the case.

like image 117
utnapistim Avatar answered Nov 02 '22 22:11

utnapistim


Yes, normally (or at least sometimes) it would be implemented in a way that you can make it compatible with a "C-hack", but the details differs from compiler to compiler.

This becomes quite natural for a few reasons:

  • C is/was designed to allow for low-level programming which would suggest that all data-types available on the processor would be available to a C implementation as well.
  • The implementations of C/C++ are often bundled into the same product, which will result in a lot of shared code, the fundamental data types used in C++ could therefore easily be done available in C.
  • The data types required for the class layout are basically the already present types of C/C++ language.

Basically, it's "easy" to implement C++ in a way that the class layout could be described in the accompanying C implementation, but also it's "harder" not to do it.

As a simple case of GCC layout we can consider a class with virtual methods (if it has no virtual method it would be a plain struct layoutwise). The layout will then start with the virtual table pointer which points to an array of words/pointers (containing both function pointers, pointer to the type_info node, and some other useful information). Then follows the members as if it were a normal struct.

When inheriting it's similar, it starts with the layout of the base class (natural since the pointer to the derived class should be easy to cast to a pointer of the base class) except now the virtual table pointer points to the virtual table of the derived class (which by the way has the same layout as the base class except it may have additional elements corresponding to new virtual methods introduced in the derived class - here to a pointer to the virtual table of the derived class can function as the virtual table of the base class).

In C this would look something like:

struct class_layout {
     void **__vptr;

     /* 
     base data members as they appear in the C++ definitions,
     (given they have fundamental types)
      */

     /*
      additional data members introduced in the derived class
     */
};

It would be tempting to define __vptr as a pointer to a struct that contains the function pointers, it would work fine except it would not be that compatible with how GCC does it. The detail is that there are entries in the virtual table at negative indices as well (probably for historical reasons).

Then there are some cases that require special care: A base class that doesn't have virtual methods for example would (almost) require that there is no virtual table pointer in the base class. The case of virtual inheritance would require a pointer to the base class object.

like image 36
skyking Avatar answered Nov 03 '22 00:11

skyking