面试题:空指针能访问成员函数吗? ex: A* p=nullptr;p->f();

旅行   2024-10-22 11:54   广东  

欢迎关注本公众号,专注面试题拆解

分享一套视频课程:《C++实现百万并发服务器》 面试需要项目的可以找我获取
,免费分享。 欢迎V:fb964919126
网络编程系列,已经更新4篇,欢迎阅读:网络编程







空指针能访问成员函数吗?ex: A* p=nullptr;p->f();





看到这道题首先一愣,第一反应这么写不对,但是这是腾讯的面试题,仔细一想,有点意思啊,平时还真是不会去这么思考问题。这是在考成员函数的位置呢,如果直接问成员函数存放在哪里,大部分人能回答上来,换这种问法即使心理有想法,自己没有实际代码编译一下,也不太敢直接回答。(mmp的,面试官这样有意思吗)


我们直接代码实践:

测试验证1:

#include <iostream>class A{public:  void func(){    std::cout << "func" << std::endl;  }};int main(){  A* p = nullptr;  p->func();  return 0;}

运行结果:正常打印输出,程序也没有崩溃。


测试验证2:虚函数

#include <iostream>class A{public:  void func(){    std::cout << "func" << std::endl;  }
  virtual void func2(){ std::cout << "func2" << std::endl; }};int main(){ A* p = nullptr; p->func(); p->func2();
return 0;}

运行结果:程序崩溃。

测试验证3:非静态成员变量

#include <iostream>class A{public:  void func(){    std::cout << "func" << std::endl;  }
int k = 0;};int main(){ A* p = nullptr; p->func(); p->k = 9;
return 0;}

运行结果:程序崩溃。

测试验证4:静态成员变量

#include <iostream>class A{public:  void func(){    std::cout << "func" << std::endl;  }  static int k;};int A::k = 0;int main(){  A* p = nullptr;  p->func();  p->k = 9;
return 0;}

运行结果:正常没有崩溃



我们回到测试1,看下它的汇编代码:

可以看到:它底层调用的方式是:A::func

成员函数的位置:

在C++中,类的成员函数并不是存储在类的实例(对象)本身中,而是存储在程序的全局代码段(通常是.text段)中


类的成员函数实际上是普通的函数,它们被编译成机器码,并存储在程序的全局代码段中。这意味着所有的成员函数都是共享的,并不是每个对象都有自己的副本


如果类中定义了虚函数,那么每个对象会包含一个指向虚拟表的指针。虚拟表是一个数据结构,它存储了虚函数的地址。这样,当调用虚函数时,程序可以根据对象的实际类型找到正确的函数地址。


成员函数的调用方式:

非虚函数

对于非虚函数,编译器通过调整成员函数的调用机制来实现。具体来说,编译器会将成员函数转换为一个带有额外参数的普通函数,这个参数通常是对象的指针或引用来代替this指针。


class MyClass {public:    void nonVirtualFunc() {        // 成员函数体    }};
// 成员函数的实际调用MyClass obj;obj.nonVirtualFunc(); // 实际上编译器转化为 MyClass::nonVirtualFunc(&obj);

虚函数:

对于虚函数,编译器会生成一个虚拟表(vtable),并在每个对象中存储一个指向该虚拟表的指针。当调用虚函数时,程序会根据this指针指向的虚拟表来查找并调用正确的函数。

class MyClass {public:    virtual void virtualFunc() {        // 成员函数体    }};
// 成员函数的实际调用MyClass obj;obj.virtualFunc(); // 实际上编译器转化为 (*obj.vptr)->virtualFunc(&obj);

空指针访问成员函数:

这个本质上要看是否使用到了this指针,如果用到了就会发生崩溃,测试代码1如果改一下,func函数里面打印k的值,也会发生崩溃,因为访问k就是调用了this->k。

#include <iostream>class A{public:  void func(){    std::cout << "func" << k << std::endl;  }  int k = 9;};


总结:

类的成员函数并不是存储在类的实例本身中,而是存储在程序的全局代码段中,空指针访问成员函数,如果没有用到this不会出错。

end



CppPlayer 



关注,回复【电子书】珍藏CPP电子书资料赠送

精彩文章合集

专题推荐

【专辑】计算机网络真题拆解
【专辑】大厂最新真题
【专辑】C/C++面试真题拆解

CppPlayer
一个专注面试题拆解的公众号
 最新文章