views:

140

answers:

6

This is more a curiosity than anything else...

Suppose I have a C++ class Kitty as follows:

class Kitty
{
    void Meow()
    {
        //Do stuff
    }
}

Does the compiler place the code for Meow() in every instance of Kitty?

Obviously repeating the same code everywhere requires more memory. But on the other hand, branching to a relative location in nearby memory requires fewer assembly instructions than branching to an absolute location in memory on modern processors, so this is potentially faster.

I suppose this is an implementation detail, so different compilers may perform differently.

Keep in mind, I'm not considering static or virtual methods here.

+1  A: 

I believe the standard way for instance methods is to be implemented like any static method, only once, but having the this pointer passed on a specific register or on the stack to perform the call.

Julien Lebosquain
+1  A: 

No, the compiler only generates the code for Meow once and each Kitty instance uses that provided the member was compiled out-of-line. If the compiler is able to and chooses to inline the function then it gets duplicated at each point of use (rather than with every instance of a Kitty).

Troubadour
+4  A: 

In the usual implementation, there's only one copy of any given function. The association between the code and the data for a given object instance is established by passing a hidden parameter (referred to a this in the function) that's a pointer to the object instance (and its data).

For virtual functions, things get a bit more convoluted: each class gets a vtable that holds a set of pointers to the virtual functions, and each object gets a pointer to the vtable for its class. The virtual functions are invoked by finding the vtable pointer, looking at the correct offset, and invoking the function pointed to by that pointer.

Jerry Coffin
If I understand you correctly, under the hood it is doing what Python explicitly does on every member function, requiring the reference to the instance. Yes?
Mashmagar
Regardless of whetheer you explicitly use the `this` pointer when accessing a member function or member variable, it is always used. In the case of member functions, that means passing `this` to the member function as its first (invisible) parameter. If it's a virtual function, the virtual table complicates things, but essentially, you're always passing the `this` pointer to member functions as their first paramater. That's why certain operator overloads (like `<<`) have to be friend functions rather than member functions.
Jonathan M Davis
@Mashmagar: yes, the two are fairly similar.
Jerry Coffin
+2  A: 

No, this is not the way it is done.
Methods that are not virtual are exactly the same as any other function but with an additional argument for the this pointer.

Methods that are virtual are invoked using a v-table. the v-table is a list of function pointers which are stored next to the objects data. In a sense, this is closer to what you describe but still, the body of the function is always the same for all instances of the object.
This can be demonstrated if you have a static variable in the method. The static variable is going to be the same for methods invoked from different instances.

shoosh
Actually, most implementations place a *pointer* to the vtable in the object and not the vtable itself. This pointer is often called the *vptr*.
FredOverflow
A: 

The compiler creates an entry for every class (not object) inside its own data structure. This entry for the class contains pointers to the methods for that class.

An object is represented in memory as a pointer to the parent class and a collection of its instance fields (since these are different for every object.) Then when a method is called, the object follows the pointer to its parent which then follows the pointer to the appropriate method. A pointer to the object is also supplied to the method, which acts as the this pointer.

Virtual methods are a little more complicated, but they are done in a similar way.

If you want to know more, see if you can take a programming languages class.

Here's a poor attempt at ASCII art to explain it:

 obj                        class
+------------+            +----------+
| ptrToClass |----------->| method1  | ----------> toSomewhere(ptrToObj)
|------------|            |----------|
| field1     |            | method2  | ----------> toSomewhereElse(ptrToObj)
+------------+            +----------+
samoz
+2  A: 

Because you have the definition of Meow inside the class definition, Meow is implicitly inline.

inline is a hint to the compiler to replace the call with the actual contents of the function. But it is only a hint - the compiler may choose to ignore the hint.

If the compiler abides by the hint, each call will be replaced with the function contents. That means the compiler will generate the code each time Meow is called instead of generating a function call.

If the compiler ignores the hint, the compiler/linker will arrange for there to be a single version that all calls will be directed to (because it is inline, a classic strategy is that every translation unit that uses the function will get a separate copy with instructions to the linker to keep only one version).

Finally, let's move into explanations where the function is not inline. In this case, it is required for the coder to make sure the definition appears in exactly one translation unit and all calls will be sent to this one version.

R Samuel Klatchko