Where does the compiler store methods for C++ classes?
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开发者_JAVA技巧'm not considering static or virtual methods here.
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.
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.
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.
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.
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
).
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)
+------------+ +----------+
精彩评论