静态成员函数:
在C++编译器中会把静态成员变量当作全局变量处理,如同全局变量一样将其放在静态、全局变量区(栈区),只不过其可见性限制为类对象区域。
非静态成员函数:
C++并不会将每个非静态成员函数的代码放在每个类对象中,而是根据类名维护所有的成员函数,当通过某个类对象调用成员函数时会如同调用普通函数一样进行调用,只不过在函数参数列表中添加了一个额外的参数:this指针。
看以下代码:
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
int a;
virtual void v_func()
{
cout<<"v_func"<<endl;
}
void func()
{
cout<<"func"<<endl;
}
};
int main()
{
int* b = new int(0);
A* a = (A*)(b);
a->func();//可以正常输出
a->v_func();//崩溃
return 0;
}
将一个int指针强转为A指针后是可以调用A类的成员函数的,因为编译器根据类型A确定要执行的函数(如果成员函数中使用了成员变量,同样会崩溃,因为此类并没有构造)。
但是调用虚函数会出问题,因为虚函数是要通过虚函数表来确定函数地址,每个类对象会有一个虚函数表指针vptr指向虚函数表,而此类对象没有构造,是找不到它的vptr的。
再看下面这段代码
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
int a;
virtual void v_func()
{
cout<<"v_func_A"<<endl;
}
void func()
{
cout<<"func_A"<<endl;
}
};
class B:public A
{
public:
int a;
virtual void v_func()
{
cout<<"v_func_B"<<endl;
}
void func()
{
cout<<"func_B"<<endl;
}
};
int main()
{
B b;
A a = b;
A* pa = &b;
a.func();
a.v_func();
pa->func();
pa->v_func();
int k;
cin>>k;
return 0;
}
输出:
func_A
v_func_A
func_A
v_func_B
对于a.func()和pa->func(),func为普通成员函数,编译器将直接根据类型A进行函数调用,所以都是执行A的func函数。
对于a.v_func(), v_func()为虚函数,应该是通过vptr查找虚函数表进行函数调用的,但是将b对象直接赋值给a时,编译器会将b对象中的A类部分拷贝给a,超出A的部分将发生截断,同时会将a的vptr设为A类的虚函数表地址,所以调用v_func()是从A的虚函数表中取得v_func函数代码的地址,执行的是A的v_func函数。
对于pa->v_func(),就是多态行为了,由于只是指针赋值,所以编译器会将pa的值设为b对象的地址,但是内存中的vptr的值没有改变,还是B得虚函数表地址,所以会调用B的v_func()函数。
静态成员函数
对于静态成员函数,编译器对其处理方式与普通成员类似,不过静态成员函数不依赖于具体类对象存在,所以进行静态成员函数调用时编译器不会自动在参数列表中插入this指针,编译器对静态成员函数的处理与全局函数的处理是差不多的