c++ 静态绑定和动态绑定

news/2024/10/22 13:42:48/

  C++ 中有两种不同的函数调用方式:静态绑定和动态绑定。

静态绑定

  静态绑定是指在编译时确定调用哪个函数。也就是说,编译器会根据函数调用的名称和参数类型来确定要调用的函数。这种方式也被称为静态多态或编译时多态。

静态绑定适用于以下情况:

  1. 在编译时已经知道调用哪个函数。
  2. 函数的名称和参数类型是确定的。
  3. 函数调用的目标是一个静态类型的对象。

例如:

class Shape {
public:void draw() {cout << "Drawing shape" << endl;}
};class Circle : public Shape {
public:void draw() {cout << "Drawing circle" << endl;}
};int main() {Circle c;Shape* s = &c;s->draw(); // 静态绑定,输出 Drawing shapereturn 0;
}

  上述代码中,调用s->draw()函数时,由于s的静态类型是Shape*,因此编译器会使用静态绑定来调用Shape::draw()函数,而不是Circle::draw()函数。

动态绑定

  动态绑定是指在运行时确定调用哪个函数。也就是说,编译器不确定要调用哪个函数,而是将函数调用委托给运行时系统来决定。这种方式也被称为动态多态或运行时多态。

动态绑定适用于以下情况:

  1. 在运行时才知道调用哪个函数。
  2. 函数的名称和参数类型不确定,只有在运行时才能确定。
  3. 函数调用的目标是一个动态类型的对象。

例如:

class Shape {
public:virtual void draw() {cout << "Drawing shape" << endl;}
};class Circle : public Shape {
public:void draw() {cout << "Drawing circle" << endl;}
};int main() {Circle c;Shape* s = &c;s->draw(); // 动态绑定,输出 Drawing circlereturn 0;
}

  上述代码中,调用s->draw()函数时,由于s的动态类型是Circle,因此运行时系统会使用动态绑定来调用Circle::draw()函数,而不是Shape::draw()函数。这就是C++中的虚函数机制,通过在函数前加上virtual关键字来实现。

空指针调用函数

#include <iostream>
using namespace std;class test {
public:void show() { cout << "I'm test" << endl; }
};int main()
{test* t = nullptr;t->show(); // 输出 I'm test
}

  上面的代码是可以正常运行的。

  在 c++ 中,类的成员函数并不与特定对象绑定,所有成员函数共用一份成员函数体,当程序编译后,成员函数的地址即已经确定。(静态绑定)

  当调用 t->show()时,实际上执行的代码是 test::show(this), 成员函数 show() 的地址在编译器就已经确定。test::show(this) 操作相当于执行了一个函数,传入的参数为 nullptr。而在 show() 函数中没有用到 this 指针,所以程序正常运行,不会报错。

如果把代码改成下面这样,程序就会 crash

#include <iostream>
using namespace std;class test  {
public:void show() {a = 2;}private:int a;
};int main()
{test* t = nullptr;t->show();
}

在 show() 函数里会执行 this->a = 2;, 而 this 指针是 nullptr, 所以会报错。

所以,空指针也不能调用虚函数,因为虚函数的地址是动态绑定的,在运行时要通过虚函数表指针 this->vptr 找到对象对应的类的虚函数表(vtbl)。此时 this 为空,就会报错


http://www.ppmy.cn/news/49123.html

相关文章

如何恢复回收站中被删除的文件?高效的恢复技巧

一般情况下&#xff0c;我们从电脑上普通删除的文件&#xff0c;会经过回收站&#xff08;除非文件过大&#xff09;&#xff0c;想要在回收站找回删除的东西&#xff0c;是很简单的&#xff0c;我们只需要打开回收站&#xff0c;找到删除的文件&#xff0c;右键点击并选择还原…

three.js(JS 三维模型库)介绍和入门

介绍&#xff1a; three.js是一个基于WebGL的JavaScript 3D库。它封装了WebGL API&#xff0c;为开发者提供了简单易用的API&#xff0c;以便在Web浏览器中展示3D图形。three.js提供了几个组件、方法和工具&#xff0c;用于创建和处理3D图形&#xff0c;使得开发者可以在Web浏…

Python 环境搭建

Unix & Linux 平台安装 Python: 以下为在 Unix & Linux 平台上安装 Python 的简单步骤&#xff1a; 打开 WEB 浏览器访问https://www.python.org/downloads/source/选择适用 于Unix/Linux 的源码压缩包。下载及解压压缩包。如果你需要自定义一些选项修改Modules/Setu…

【软件测试二】开发模型和测试模型,BUG概念篇

目录 1.软件的生命周期 2.瀑布模型 3.螺旋模型 4.增量&#xff0c;迭代 5.敏捷---scrum 1. 敏捷宣言 2.角色 6. 软件测试v模型 7.软件测试w模型 8.软件测试的生命周期 9.如何描述一个BUG 10.如何定义BUG的级别 11.BUG的生命周期 12.产生争执怎么办 1.软件的生命周期…

【Java】Java8接口中方法区别和使用

Java接口说明 jdk1.8之前接口只能是抽象方法。实现接口必须重写所有方法&#xff0c;比较麻烦。在java8中&#xff0c;支持default和static方法&#xff0c;这样&#xff0c;实现接口时&#xff0c;可以选择是否对default修饰的方法重写。 抽象方法 接口当中的抽象方法&#x…

Python datetime基本使用

time和datetime的区别 time time提供的功能更加接近操作系统层面&#xff0c;主要调用C平台的C libarary的同名函数&#xff0c;表现的日期范围仅限于1970-2038。这里的time指的是大模块的time&#xff0c;不是datetime中的time import timeif __name__ __main__:# 获取时间…

redis 主从模式、哨兵模式、cluster模式的区别

参考&#xff1a; ​https://blog.csdn.net/qq_41071876/category_11284995.html https://blog.csdn.net/weixin_45821811/article/details/119421774 https://blog.csdn.net/weixin_43001336/article/details/122816402 Redis有三种模式&#xff0c;分别是&#xff1a;主…

kafka集群topic重新分配leader

1.案例 当kafka集群的broker节点宕机重启后,此broker节点的partition分区的leader节点会被选举为其它broker节点,此broker节点恢复后就会导致配分不均衡 可以看到所有partition的leader节点都在broker id为1的节点上,原来是平均分配到3个broker节点上,replicas项的首位…