您的位置:首页 > 编程语言 > C语言/C++

C++调用空指针对象的成员函数——静态绑定与动态绑定

2016-08-06 13:31 423 查看
最近代码中看到调用空指针对象的成员函数的写法,联想起上次碰到的问题:

C++类的成员函数存储方式(是否属于类的对象)

两者的本质是一样的,上次只是简单地讨论了下,这次从编译器的角度,来谈一谈这个知识点。

一个简单的例子:

class MyClass
{
public:
int i;
void hello()
{
printf("hello\n");
}
void print()
{
printf("%d\n", i);
}
};
void main()
{
MyClass* pmy = NULL;
pmy->hello();
}


“静态绑定”和“动态绑定”的区别

以下面的语句为例:

somenull->foo();


该语句的意图是:调用对象somenull的foo成员函数。

这句话在Java或Python等动态绑定的语言之中,编译器生成的代码大概是:

找到对象somenull的foo成员函数,调用它。(注意,这里的找到是程序运行的时候才找的,这也是所谓动态绑定的含义:运行时才绑定这个函数名与其对应的实际代码。有时也叫迟绑定。)

而对于C++,为了保证程序的运行时效率,C++的设计者认为凡是编译时能确定的事情,就不要拖到运行时再查找了。所以C++的编译器看到这句话会这么干:

1、查找somenull的类型B,发现该类型有一个非虚的成员函数叫foo。

2、找到了,在这里生成一个函数调用,直接调B::foo(somenull)。

所以到了运行时,由于foo()函数里面并没有任何需要解引用somenull指针的代码,所以真实情况下也不会引发segment fault。这里对成员函数的解析,和查找其对应的代码的工作都是在编译阶段完成而非运行时完成的,这就是所谓的静态绑定,也叫早绑定。

因此上述代码能够正确运行的真正原因是:对于非虚成员函数,C++这门语言是静态绑定的。

在C++中,每个对象都有一个指向自己的this指针,它的作用主要就是用来区分不同的对象,这样你就可以根据它来访问不同的对象的成员变量。

编译器编译后的成员函数的第一个参数是this指针,通过this指针引用数据成员及调用其它成员函数。

MyClass* pmy = NULL;
pmy->hello();


实际上相当于:

MyClass::hello(NULL);


hello函数并没有使用类中的任何成员变量,所以,它也就不会用到this指针,即使此时的this指针是NULL,也不妨碍我们使用hello函数,然而,如果你调用pmy->print(),那么将会报空指针错误,因为这个函数试图用this指针访问成员变量i,而此时this为NULL。

需要注意的是,虚函数一般是动态绑定的~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: