本文探索执行对象的空指针调用成员函数时会发生什么。
以下面的简单类来示例:
#include<iostream>
using namespace std;
class TestNullPtr {
public:
void print() {
cout << "print" << endl;
}
void getA() {
cout << a << endl;
}
void setA(int x) {
a = x;
}
virtual test() {
cout << "test" << endl;
}
private:
int a = 100;
};
上面的代码中为类TestNullPtr定义了四个方法,分别是print
,getA
,setA
,test
。这四个方法的作用分别是打印字段,打印类的元素a,修改类元素a,虚方法。
I、空指针调用成员函数测试
1、我们先来看调用print
方法会发生什么:
int main() {
TestNullPtr* ptr = nullptr;
ptr->print();
}
运行结果成功执行并正确打印:
2、再看调用getA
会发生什么:
int main() {
TestNullPtr* ptr = nullptr;
ptr->getA();
}
程序虽然不会编译报错,但返回的是一个错误码,也没有正常执行:
3、再看调用setA
会发生什么:
int main() {
TestNullPtr* ptr = nullptr;
ptr->setA(99);
}
可以看到结果与调用getA
相同:
4、再看调用test
虚方法会发生什么:
程序可以运行,但是返回错误码,没有执行对应代码:
II、测试结果分析
首先,类的成员函数并不与特定对象绑定,所有成员函数共用一份成员函数体,当程序编译后,成员函数的地址即已经确定。那为什么同一个类的不同对象调用对应成员函数可以出现不同的结果呢,答案就是this指针。
共有的成员函数体之所以能够把不同对象的数据区分开来,靠的是隐式传递给成员函数的this指针,成员函数中对成员变量的访问都是转化成"this->数据成员"的方式。因此,从这一角度说,成员函数与普通函数一样,只是多了一个隐式参数,即指向对象的this指针。
因此当所调用的成员函数有需要访问对象元素(getA)或者更改对象元素值(setA)时,由于没有this指针(因为现在this指针指向的是nullptr),就会导致不能正确执行。
同理,因为虚方法的调用是依赖于this指针的,所以同样会产生错误。
其实,上例中的print
方法,并不是成员函数,其只是在类中定义的普通函数。
网友评论