C++之静态绑定和动态绑定

本文详细解释了静态绑定和动态绑定的概念,通过示例代码展示了它们在C++中的应用及区别,包括如何通过虚函数实现动态绑定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

静态绑定(statically bound):又名前期绑定(eraly binding),绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期;
动态绑定(dynamically bound):又名后期绑定(late binding),绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期;(要求基类必须有virtual,否则执行的是静态绑定)

  • 静态绑定发生在编译期,动态绑定发生在运行期;
  • 对象的动态类型可以更改,但是静态类型无法更改;
  • 要想实现动态,必须使用动态绑定;
  • 在继承体系中只有虚函数使用的是动态绑定,其他的全部是静态绑定;

实例1:静态绑定和动态绑定

#include <iostream>

class A
{
public:
    virtual void func(){ std::cout << "A::func()\n"; }
};
class B : public A
{
public:
    void func(){ std::cout << "B::func()\n"; }
};
class C : public A
{
public:
    void func(){ std::cout << "C::func()\n"; }
};

int main()
{
    B *pb = new B();    动态和静态类型均是B类
    C *pc= new C();     动态和静态类型均是C类
    A *pa  = pc;           静态类型为A类,动态类型为C类
    C *pnull = NULL;   静态类型为A类,动态类型为NULL

    pa->func();
    pb->func();
    pc->func();

    pnull->func();

}

(1)基类没有virtual,静态绑定调用静态类型

A::func()
B::func()
C::func()

C::func()

(2)如果删除C类中的func函数,其结果是

A::func()
B::func()
A::func()
A::func()   调用基类的函数

(3)如果仅仅在A类中增加virtual函数,其结果是

(基类有virtual,动态绑定调用动态类型)

C::func()
B::func()
C::func()

段错误(吐核)

如果C类中未重写func函数,则输出结果为(使用基类函数)

A::func()
B::func()
A::func()


实例2- 动态绑定注意默认参数的使用

#include <iostream>

class E
{
public:
    virtual void func(int i = 0)
    { 
        std::cout << "E::func()\t"<< i <<"\n";
    }
};
class F : public E
{
public:
    void func(int i = 1)
    {
        std::cout << "F::func()\t" << i <<"\n";
    }
};

int main()
{
    F* pf = new F();
    E* pe = pf;
    pf->func();
    pe->func(); 
    pf->func(4);

    pe->func(5); 

    return 0;
}

[root@localhost cplusplus]# ./a.out 
F::func() 1
F::func() 0   (默认参数需要静态绑定,而virtual使用动态绑定,冲突)
F::func() 4
F::func() 5

绝对不要重新定义一个继承而来的virtual函数的缺省参数值,因为缺省参数值都是静态绑定(为了执行效率),而virtual函数却是动态绑定

如果F类不定义默认参数时,F::func() 编译时报错提醒。


注意:

(1)一旦基类是virtual函数,则派生类不能改变virtual的属性,派生类可保留virtual属性

(2)用作基类的类必须是已定义的。如 class A; 仅仅是申明,是不能作为基类的

(3)派生类也可作为基类,对于最底层的派生类来说是直接基类,最上层则是间接基类



### C++ 静态绑定动态绑定的概念及区别 #### 1. **静态绑定 (Static Binding)** 静态绑定是在编译期间完成的方法对象之间的绑定过程。这意味着当代码被编译时,编译器已经能够确定应该调用哪个具体的函数或方法[^1]。这种绑定通常用于非虚函数以及不涉及继承关系的简单函数调用场景。 静态绑定的主要特点如下: - 绑定发生在编译期,因此性能较高,因为无需在运行时解析实际调用的对象类型。 - 对象的静态类型决定了所调用的具体函数版本。 - 不支持多态行为,即无论指针或引用指向的实际对象是什么类型,都会按照声明时的静态类型调用对应的函数。 以下是静态绑定的一个示例: ```cpp #include <iostream> using namespace std; class Base { public: void display() { cout << "Base::display()" << endl; } }; class Derived : public Base { public: void display() { cout << "Derived::display()" << endl; } }; int main() { Base b; Derived d; Base* ptr = &b; ptr->display(); // 输出: Base::display() ptr = &d; ptr->display(); // 输出: Base::display() } ``` 在这个例子中,`ptr->display()` 的调用完全由 `Base` 类型决定,即使 `ptr` 实际指向的是 `Derived` 对象,仍然只会调用基类的 `display` 函数[^2]。 --- #### 2. **动态绑定 (Dynamic Binding)** 动态绑定则是指在运行时期间才确定应调用哪一个具体函数的过程。它主要用于处理具有继承结构并定义了虚函数的情况。在这种情况下,最终调用的函数取决于对象的真实类型而非其静态类型[^3]。 为了实现动态绑定C++ 提供了一种特殊的成员函数——**虚函数**(virtual function),并通过一种称为“虚函数表”的内部数据结构来管理这些函数的映射关系。每当创建派生类实例时,相应的虚函数会被加入到该表中,从而使得运行时刻可以根据真实类型的索引来定位正确的函数实现[^4]。 下面是一个关于动态绑定的例子: ```cpp #include <iostream> using namespace std; class Base { public: virtual void display() { cout << "Base::display()" << endl; } // 声明为虚函数 }; class Derived : public Base { public: void display() override { cout << "Derived::display()" << endl; } }; int main() { Base b; Derived d; Base* ptr = &b; ptr->display(); // 输出: Base::display() ptr = &d; ptr->display(); // 输出: Derived::display() } ``` 这里的关键在于 `Base` 类中的 `display` 方法被标记为虚拟 (`virtual`),这允许程序在运行时依据 `ptr` 所指向的实际对象类型去选择合适的重写版 `display` 来执行。 --- ### 总结对比 | 特性 | 静态绑定 | 动态绑定 | |---------------------|-----------------------------------|----------------------------------| | 发生时间 | 编译期 | 运行期 | | 支持多态 | 否 | 是 | | 使用条件 | 没有继承或者未使用虚函数 | 存在继承链且存在至少一个虚函数 | | 效率 | 较高 | 略低 | 尽管动态绑定提供了更大的灵活性支持真正的面向对象特性如多态,但它也引入了一些额外开销,比如维护虚函数表所需的内存空间以及查找合适函数的时间成本。然而,在许多现代硬件架构下,这部分差异几乎可以忽略不计。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值