C++ :静态绑定与动态绑定

本文详细解释了C++代码中的多态行为,包括虚函数、对象切片、静态绑定与动态绑定的区别,以及RTTI在选择虚函数中的作用。通过实例说明了如何避免函数调用的歧义问题。
摘要由CSDN通过智能技术生成

看下面这段代码

#include<iostream>
using namespace std;
struct A{
	int num=10;
    virtual void fun(){
        cout<<"a:"<<num<<endl;
    }
};
struct B:public A{
	B(){num=20;}
    virtual void fun(){
        cout<<"b:"<<num<<endl;
    }
};
int main() {
    A*a=new B;
    A b=B();
    A c;
    B d;
    a->fun();
    b.fun();
    c.fun();
    d.fun();
}

这段代码中发生了一次多态一次对象切片以及三次静态绑定,下面是对应主函数内的中间代码

main ()
{
  void * D.36444;//临时变量,用于存储new B的返回值
  struct B D.36464;//临时变量,用于存储B()的返回值
  int D.40095;//临时变量,用存储主函数的返回值
  {
    struct A * a;
    struct A b;
    struct A c;
    struct B d;

    try
      {
        D.36444 = operator new (16);
        try//执行new B为临时变量赋值
          {
            B::B (D.36444);
          }
        catch
          {
            operator delete (D.36444, 16);
          }
        a = D.36444;//临时变量为a赋值
        B::B (&D.36464);//调用B()为临时对象赋值
        try//调用切片构造函数只取D中A的成员为b的成员构造
          {
            A::A (&b, &D.36464.D.36395);
          }
        finally
          {
            D.36464 = {CLOBBER};//清除临时变量
          }
        _1 = &_ZTV1A + 16;//栈帧内指针移动预留出16字节空间,下面三行相当于无参构造内容
        c._vptr.A = _1;
        c.num = 10;
        B::B (&d);//定义了构造函数调用对应的构造函数
        _2 = a->_vptr.A;//取出a的虚表指针
        _3 = *_2;//定位到虚表
        OBJ_TYPE_REF(_3;(struct A)a->0) (a);//RTTI机制,根据虚表选择对应的虚函数,这里的0是偏移量(或者可以理解为索引)
        A::fun (&b);//下面三个都是静态绑定
        A::fun (&c);
        B::fun (&d);
      }
    finally//清除临时变量
      {
        b = {CLOBBER};
        c = {CLOBBER};
        d = {CLOBBER};
      }
  }
  D.40095 = 0;
  return D.40095;
}

需要注意的是在C++中使用指针调用虚函数时都会触发RTTI机制进行虚函数的选择,别的情况下都会采取静态绑定(别扯引用,引用的实现也脱离不了指针),所以说动态多态只能发生在父类对象或引用接收子类的过程中,子类对象构造父类对象的时候不会发生。

OBJ_TYPE_REF(_3;(struct A)a->0) (a);这里a进行了强制类型转化,它的作用很关键,理解起来可以从下面这个例子入手。

struct A{
    virtual void fun(int a=1){
        cout<<"a:"<<a<<endl;
    }
    
};
struct B:public A{
	void fun(){
        cout<<"B:"<<a<<endl;
    }
    virtual void fun(int a=2){
        cout<<"b:"<<a<<endl;
    }
};
int main(){
	A*a=new B;
    a->fun();
}

运行结果是b:1而不会在选择的时候被B::fun()碰瓷,这就是因为声明了a的类型,然后它直到了去哪里找普通函数,从而避免了函数调用不明的情况。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值