If your function isn't virtual then there is no overhead of being a member function (aka method).
In fact, in generated object code there is no such notion of a "member function" (unless it's virtual, more on that later). All methods are functions with special variable this
. Compiler at the compile time knows what method is to be called at the run time, so it can generate method-specific object code (with some handling of this
). By the way, that's the case why the following code doesn't crash:
#include <iostream>
class Crashy {
public:
void wouldItCrash() {
std::cout << "Hey, I'm still alive!" << std::endl;
}
};
int main() {
Crashy* ptr = 0;
ptr->wouldItCrash();
return 0;
}
Despite of null pointer there, programs successively finishes and prints "Hey, I'm still alive!"
. And that's okay if you think about method wouldItCrash
as some kind of a function with special parameter this
:
#include <iostream>
void Crashy__wouldItCrash(Crashy *this) {
std::cout << "Hey, I'm still alive!" << std::endl;
}
int main() {
Crashy* ptr = 0;
Crashy__wouldItCrash(ptr);
return 0;
}
We don't dereference the pointer in function, so no problems happen.
Consider the following simple program:
#include <iostream>
void FunctionName__() {
std::cout << "Hello from function!" << std::endl;
}
class ClassName__ {
public:
void MethodName1__() {
std::cout << "Hello from method 1!" << std::endl;
}
void MethodName2__() {
std::cout << "Hello from method 2!" << std::endl;
}
};
int main() {
FunctionName__();
ClassName__ a;
a.MethodName1__();
a.MethodName2__();
return 0;
}
If you compile it without optimizations (just g++ main.cpp
) and then look at the symbols table (nm a.out
), you'll see
0804876d T _Z14FunctionName__v
...
0804882c W _ZN11ClassName__13MethodName1__Ev
08048858 W _ZN11ClassName__13MethodName2__Ev
That is, all methods became just plain functions with special names (so no conflict could happen, see name mangling)
Virtual functions
As I said earlier, there are some special rules applying to the virtual functions. Virtual functions cannot be resolved at the compile-time (compiler doesn't know which instance of derived class will be processed at the run-time), so it's delayed to the run-time. So in order to serve virtual functions, each class (with that kind of functions, of course) has a special lookup table named virtual method table (aka vtable). In that case you clearly pay some memory space: you need a pointer to the function in the vtable and a pointer to the vtable for each instance of your class.