虚成员函数(虚函数)调用方式
class MYACLS { public: int m_i; void myfunc(int abc) { //m_i += abc; //这里需要用到this指针,而this指针为空,则会报告异常 mystfunc(); } virtual void myvirfunc() { printf("myvirfunc()被调用,this = %p\n", this); } }; int main() { //一:虚成员函数(虚函数)调用方式 MYACLS myacls; myacls.myvirfunc(); //用对象调用虚函数,就像调用普通成员函数一样,不需要通过虚函数表 MYACLS *pmyacls = new MYACLS(); pmyacls->myvirfunc(); //要通过虚函数表指针查找虚函数表,通过虚函数表在好到虚函数的入口地址,完成对虚函数的调用 delete pmyacls; return 0; }
- 反汇编
- pmyacls->myvirfunc(); 编译器视角解析
- (*(pmyacls->vptr[0]))(pmyacls);
- a)vptr,编译器给生成的虚函数表指针,指向虚函数表
- b)[0] 虚函数表中第一项。代表myvirfunc()地址
- c)传递一个参数进去,就是this,也是编译器给加的
- d)*就得到了虚函数的地址;
class MYACLS { public: int m_i; virtual void myvirfunc() { printf("myvirfunc()被调用,this = %p\n", this); //myvirfunc2(); // 通过虚函数表指针调用 MYACLS::myvirfunc2(); //直接调用虚函数,效率更高。这种写法压制了虚拟机制,不再通过查询虚函数表来调用 //这种用类名::虚函数名()明确调用虚函数的方式等价于直接调用一个普通函数; } virtual void myvirfunc2() { printf("myvirfunc2()被调用,this = %p\n", this); } }
- 注意:在类成员函数中调用用类名::虚函数名()明确调用虚函数的方式等价于直接调用一个普通函数
- 虚函数的地址也是在编译时就确定好了。
printf("MYACLS::myvirfunc2虚函数的地址为%p", &MYACLS::myvirfunc2);
- linux下采用如下方式打印某虚函数地址
静态成员函数调用方式
class MYACLS { public: //静态成员函数 //static int m_si; static void mystfunc() //不需要this参数 { printf("mystfunc()被调用\n"); //m_si = 1; } }; int main() { MYACLS myacls; MYACLS *pmyacls = new MYACLS(); myacls.mystfunc(); pmyacls->mystfunc(); MYACLS::mystfunc(); ((MYACLS *)0)->mystfunc(); //能够正常调用静态成员函数 ((MYACLS *)0)->myfunc(12); //支持这种语法是因为有些成员函数希望支持独立于类对象之外的存取操作; delete pmyacls; return 1; }
- 反汇编
静态成员函数特性
- 静态成员函数没有this指针
- 无法直接存取类中普通的非静态成员变量
- 静态成员函数不能在后使用const,也不能设置为virtual
- 可以用类对象调用,但不非一定要用类对象调用
- 静态成员函数等同于非成员函数(像个全局函数一样),有的需要提供回调函数的这种场合,可以将静态成员函数作为回调函数
- 打印静态成员函数地址
printf("MYACLS::mystfunc()地址 = %p\n", MYACLS::mystfunc);