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

最近代码中看到调用空指针对象的成员函数的写法,联想起上次碰到的问题:

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。

需要注意的是,虚函数一般是动态绑定的~

时间: 2024-09-27 08:25:18

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

为什么通过空指针(NULL)能够正确调用类的部分成员函数

#include <iostream> using namespace std; class B { public: void foo() { cout << "B foo " << endl; } void pp() { cout << "B pp" << endl; } void FunctionB() { cout << "funB" << endl; }

为什么通过空指针(NULL)可以正确调用类的部分成员函数

#include <iostream> using namespace std; class B { public: void foo() { cout << "B foo " << endl; } void pp() { cout << "B pp" << endl; } void FunctionB() { cout << "funB" << endl; }

空指针访问类成员函数

//空指针访问类成员函数 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 class Person 6 { 7 public: 8 void showinfo() 9 { 10 cout << "空指针访问成员函数成功" << endl; 11 } 12 13 void showinfo1() 14 { 15 cout << age <

成员函数指针,动态绑定(vc平台)

上一篇介绍了gcc对成员函数指针做了thunk的处理,本篇介绍vc对成员函数指针如何处理,还有动态绑定相关的处理. 同样用回上一篇的例子: struct point {float x,y;}; struct obj { virtual ~obj {} void foo(int) {} void foo(point) {} virtual void vfoo() {} }; struct objobj : public obj { virtual ~objobj {} virtual void v

c++成员函数的存储方式---11

原创博客:转载请标明出处:http://www.cnblogs.com/zxouxuewei/ 成员函数属于一个类的成员,出现再类体中.可以被指定为公有,私有或受保护的. 1.在类外面定义成员函数时,需要用类名加作用域限定符(::),如下代码: #include <iostream> #include <string> using namespace std; class _test_myclass { public: void display(const int &val

C++成员函数的存储方式

用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间. 按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元,如图8.4所示. 能否只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码.如图8.5所示. 显然,这样做会大大节约存储空间.C++编译系统正是这样做的,因此每个对象所占用的存储空间只是该对象的数据部分所占用的存储空间,而不包括函数代码所占用的存储空

C++成员函数存储

用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间. 按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元,如图8.4所示. 图8.4 能否只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码.如图8.5所示. 图8.5 显然,这样做会大大节约存储空间.C++编译系统正是这样做的,因此每个对象所占用的存储空间只是该对象的数据部分所占用的存储空间,而不包括函

const成员函数和const对象的调用关系

代码: class A{ private: int a; public: void set() { } <span style="white-space:pre"> </span>void set () const <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>} }

boost在lambda表达式中调用占位符参数的成员函数的方法

boost中提供了lambda表达式的用法,但是lambda表达式的功能还不是很强大,在其中只能对lambda的占位符参数_1等使用最基本的操作符,如+-*/,可是很多时候如果传入的占位符参数是一个对象指针的话,我们可能想要调用这个类的成员函数. 我在开发中遇到了这个问题,需要在stl的算法中传入一个函数来调用对象的比较函数,因为感觉这样太麻烦,还需要重新定义一个函数,所以想起了lambda表达式,c++11的lambda表达式我倒是没试过,可是受项目开发环境所限,只能选择boost.但是我用的