看一道面试题:
class D
{
public:
void printA()
{
cout<<"printA"<<endl;
}
virtual void printB()
{
cout<<"printB"<<endl;
}
};
int main()
{
D *d=NULL;
d->printA();
d->printB();
return 0;
}
输出结果为:
print A
Segmentation fault (core dumped)
下面进行解析:
当我们实例化一个对象的时候,因为这个对象是用类定义的,那么它理所当然拥有了这个类的数据和函数。但是,一般情况下,不同的对象,他们的的数据值不同,但是函数的代码都相同。所以,为了节约存储空间(想象一下我们如果定义了100个对象,那么用100段内存空间存储相同的代码,岂不是很浪费?),我们让成员函数的代码共享。
还可以这样理解:
类有一块内存是存放成员函数的,而每个对象申请后不会为成员函数申请内存,只是数据占有内存,当各个对象调用成员函数时,会带着this指针,自己内存中的数据,到类内存的代码段来执行。这样即使申请N个对象,但成员函数的代码只是类中那一段,而每个对象只是数据占用一部分内存。
我们把成员函数的代码存储在对象空间之外。换句话说,成员函数的代码,都不占据对象的存储空间。它会被存在其他地方。
所以类的成员函数,对于类来讲。一方面是逻辑上的“属于”,一方面是物理上的“不依赖“。
回到思考题上来,对于非静态成员函数来说,它当然是对象的一部分。(只是因为存储方式上的特殊性,容易让人误解!)
回答开头问题:
类中包括成员变量和成员函数。 new出来的只是成员变量,成员函数始终存在。 所以如果成员函数未使用任何成员变量的话,不管是不是static的,都能正常工作。
一个对象的空间=所有成员变量的大小
如果这个对象的类有虚函数的话,还可能多一个指向虚表的指针 所有函数存放在独立于对象的存储空间内 对象调用函数时,对静态成员函数直接调用不存在问题,对成员函数需要把自己以this指针传给函数以指明以哪个对象调用。
所以用未初始化的指针调用静态成员函数、或者调用未使用任何成员变量的成员函数(即未用到this指针) 从理论上都是可行的,至于具体支不支持看各个编译器吧。
之所以第二个打印会core掉,就是因为d指向NULL,即地址为0x00000000,再去找虚地址指针,肯定是找不到的。