美文网首页
动态绑定

动态绑定

作者: tingjieee_19e5 | 来源:发表于2018-04-28 10:37 被阅读0次

动态绑定

  1. 对象的静态类型:对象在声明时采用的类型,在编译期确定,静态类型无法更改
  2. 对象的动态类型:所指对象的类型,在运行期决定。对象的动态类型可以更改,
  3. 静态绑定:绑定的是对象的静态类型,发生在编译期
  4. 动态绑定:绑定的是对象的动态类型
class B{
public:
    void doSomething() {
    }
    virtual void vfun() {
    }
};
class C : public B{
public:
    void doSomething() {//子类中是一个非虚函数,这样会造成名称遮挡
    }
    virtual void vfun() {
    }
};
class D : public B {
public:
    void doSomething() { }//子类中是一个非虚函数,这样会造成名称遮挡
    virtual void vfun() {  }
}

D* pD = new D();
B* pB = pD;
// pD和pB都指向同一个对象,但是doSomething()是no-virtual函数,是静态绑定的
// 编译期会根据对象的静态类型来选择函数
pD->doSomething(); //调用的是D::doSomething()
pB->doSomething(); //调用的是B::doSomething()
//由于vfun是虚函数,它是动态绑定的,虽然pD,PB的静态类型不同,但是指向同一个对象
// 动态类型是相同的,都是D*,所以它俩调用的是同一个B::vfun()。
pD->vfun();
pB->vfun();

哪些是动态绑定哪些是静态绑定:
只有当使用指针或者引用时调用虚函数才使用动态绑定,其他的全是静态绑定。

缺省参数是静态绑定的。
具有继承关系的类之间发生类型转换:

  1. 从派生类向基类的类型转换只对指针或引用有效
  2. 基类向派生类不存在隐式类型转换
  3. 派生类向基类的类型转换可能会由于访问受限存在问题
#include <iostream>
using namespace std;
//class A final { } final 关键字可以防止继承的发生
class A {
    public:
        A() =default;
        virtual void f() const {
            cout << "A::f()" << endl;
        }
        virtual ~A() {}
};

class B : public A {
    public:
        B() =default;
        void f() const override{ // C++11 中使用override来说明派生类中的虚函数,方便清晰定位
            cout << "B::f()" << endl;
        }
        ~B(){}
};

void call(A &i){ //这里使用基类作为形参的引用,可以处理派生类和基类,实现代码复用,OOP
    i.f();
}

int main()
{
    B b;// B的内存分布中,虚函数表位于函数指针位置起始位置,B中的f()覆盖了基类的f()指针,
    A a;
    A *pB = new B;
    call(b); // 调用b的f()
    call(a); //调用 a的f();
    delete pB; 
// 先如果基类的析构函数是虚函数,则先调用基类的析构函数,在调用派生类的析构函数,如果基类的析构函数不是虚函数,则只析构基类造成泄露。
// 但是对于局部变量离开作用域,则是先调用派生的析构函数,然后在调用基类的析构函数

// b是局部变量,析构的时候不是动态绑定,因此会依次调用~B,~A。
// 但pB是A类型的,在使用delete时如果A的析构函数不是虚函数,则会只调用A的析构函数,造成子类的内存泄露
// 而如果A的析构函数是虚函数,由于存在动态绑定,并且通过指针或者引用,存在派生类向基类转换则,delete会在调用完~A,发现~A是虚函数,再调用~B,完成全部的析构。

    return 0;
}

相关文章

网友评论

      本文标题:动态绑定

      本文链接:https://www.haomeiwen.com/subject/ixawlftx.html