Hi,
I have this question in mind for many years..
C++ class provides encapsulation which encapsulate its members and
member function.
class Experiment
{
private:
int _experient;
public:
void ExpFun()
{
// Code here
}
};
Here ExpFun() is a member function, so at runtime this member function
shall have a memory where the function execuatble code reside.
Obviously there should be only one copy (Assume void ExpFun() is not
inline function) of ExpFun() in memory.
But I can create many objects for Experiment class
Experiment e1,e2, e3;
Logically we are calling the function like this
e1.ExpFun();
e2.ExpFun();
e3.ExpFun();
When the function is called, what happens?. Howcome the ExpFun() works
exactly with the corresponding member variables of the object?. Where
this pointer has been passed to ExpFun()?.
I would appreciate if someone answer me or guide a good book to get
idea about this..
Short answer first: By magic. The standard doesn't say how things should
work. The internals is implementation specific.
Below is a description of one possible way to implement the C++ object
model, which might not be 100% correct on any single existing platform
but should give you an idea on how things work in practice.
The standard speaks about different storage classes of memory, and there
are three of them: static, automatic, and free store.
Static memory is initialized at the beginning of a program, and is
never destroyed, deallocated or any such thing. Objects can be placed
in static memory, either by defining them at namespace scope, i.e
outside any function, or struct (when I say struct it also applies to
classes), or by using the static keyword inside functions and structs.
Executable code also resides in static memory. This applies to normal
functions as well as member functions, constructors, destructors etc.
So when you say something like:
struct Experiment {
void ExpFun() { /* code here */ }
};
The compiler generates the code at one place in the static memory and
label it with a name according to an implementation specific scheme.
For example it could use the name __struct_Experiment_void_ExpFun_void__
for this function.
When you later in your code call it with:
int main()
{
Experiment e;
e.ExpFun();
}
The compiler knows that e is of the type Experiment, so it just translate
the code to call the function named __struct_Experiment_void_ExpFun_void__,
almost as you would have said:
extern __struct_Experiment_void_ExpFun_void__();
int main()
{
__struct_Experiment_void_ExpFun_void__();
}
The exact naming scheme is specific to each implementation, but it's usually
quite easy to list the names. On unix systems there is the nm utility and
I guess Win32's dumpbin is similar. Sometimes the "mangled" names show up
in error messages during the linking phase too, so it can be useful to
have an idea of how things work.
So reamins the question of how the function knows where the member variables
are stored.
Suppose now that we have the following:
struct Experiment {
int member;
static int member_static;
Experiment() : member(0) { }
void ExpFun() { member_static = member; }
void ExpFun(int x) { member = x; }
static void ExpStaticFun(int x);
};
int Experiment::member_static = 42;
The compiler takes this apart and generates code for the following:
struct Experiment {
int member;
};
int __struct_Experiment_member_static__ = 42;
void __struct_Experiment_ctor_void__(Experiment * const this)
{
this->member = 0;
}
void __struct_Experiment_ExpFun_void__(Experiment * const this)
{
__struct_Experiment_member_static__ = this->member;
}
void __struct_Experiment_ExpFun_int__(Experiment * const this, int x)
{
this->member = x;
}
void __struct_static_Experiment_ExpFun_int__(int x)
{
__struct_Experiment_member_static__ = x;
}
All member functions and static member variables are stripped out
from the struct, leaving an old fashoned C struct behind. Taking
the sizeof a struct reflects this. It does not matter how many
member functions a struct has, the size is the same.
The member functions are renamed and placed next to all other
functions in the static memory, and a function argument named
"this", is automatically added, which holds a pointer to the
object the function will operate on. Note that it is only for
non static member functions that the "this" argument is added.
When a client of the struct later says:
int main()
{
Experiment e;
e.ExpFun();
e.ExpFun(12);
e.ExpStaticFun(13);
Experiment::ExpStaticFun(14);
}
It gets translated to:
int main()
{
Experiment e; /* sizeof e is allocated in automatic memory (stack) */
__struct_Experiment_ctor_void__(&e);
__struct_Experiment_ExpFun_void__(&e);
__struct_Experiment_ExpFun_int__(&e, 12);
__struct_static_Experiment_ExpFun_int__(13);
__struct_static_Experiment_ExpFun_int__(14);
}
I hope you get an idea on how things usually are implemented.
Play with your compiler and tools to see how it works in your
implementation.
/Niklas Norrthon