深入理解C++的动态绑定和静态绑定

为了支持c++的多态性,才用了动态绑定和静态绑定。理解他们的区别有助于更好的理解多态性,以及在编程的过程中避免犯错误。
需要理解四个名词:
1、对象的静态类型:对象在声明时采用的类型。是在编译期确定的。
2、对象的动态类型:目前所指对象的类型。是在运行期决定的。对象的动态类型可以更改,但是静态类型无法更改。
关于对象的静态类型和动态类型,看一个示例:

view plaincopy to clipboardprint?
class B  
{  
}  
class C : public B  
{  
}  
class D : public B  
{  
}  
D* pD = new D();//pD的静态类型是它声明的类型D*,动态类型也是D*  
B* pB = pD;//pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D*  
C* pC = new C();  
pB = pC;//pB的动态类型是可以更改的,现在它的动态类型是C* 
class B
{
}
class C : public B
{
}
class D : public B
{
}
D* pD = new D();//pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB = pD;//pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D*
C* pC = new C();
pB = pC;//pB的动态类型是可以更改的,现在它的动态类型是C*
 

3、静态绑定:绑定的是对象的静态类型,某特性(比如函数)依赖于对象的静态类型,发生在编译期。
4、动态绑定:绑定的是对象的动态类型,某特性(比如函数)依赖于对象的动态类型,发生在运行期。
view plaincopy to clipboardprint?
class B  
{  
    void DoSomething();  
    virtual void vfun();  
}  
class C : public B  
{  
    void DoSomething();//首先说明一下,这个子类重新定义了父类的no-virtual函数,这是一个不好的设计,会导致名称遮掩;这里只是为了说明动态绑定和静态绑定才这样使用。  
    virtual void vfun();  
}  
class D : public B  
{  
    void DoSomething();  
    virtual void vfun();  
}  
D* pD = new D();  
B* pB = pD; 
class B
{
    void DoSomething();
    virtual void vfun();
}
class C : public B
{
    void DoSomething();//首先说明一下,这个子类重新定义了父类的no-virtual函数,这是一个不好的设计,会导致名称遮掩;这里只是为了说明动态绑定和静态绑定才这样使用。
    virtual void vfun();
}
class D : public B
{
    void DoSomething();
    virtual void vfun();
}
D* pD = new D();
B* pB = pD;

让我们看一下,pD->DoSomething()和pB->DoSomething()调用的是同一个函数吗?
不是的,虽然pD和pB都指向同一个对象。因为函数DoSomething是一个no-virtual函数,它是静态绑定的,也就是编译器会在编译期根据对象的静态类型来选择函数。pD的静态类型是D*,那么编译器在处理pD->DoSomething()的时候会将它指向D::DoSomething()。同理,pB的静态类型是B*,那pB->DoSomething()调用的就是B::DoSomething()。

让我们再来看一下,pD->vfun()和pB->vfun()调用的是同一个函数吗?
是的。因为vfun是一个虚函数,它动态绑定的,也就是说它绑定的是对象的动态类型,pB和pD虽然静态类型不同,但是他们同时指向一个对象,他们的动态类型是相同的,都是D*,所以,他们的调用的是同一个函数:D::vfun()。

上面都是针对对象指针的情况,对于引用(reference)的情况同样适用。

指针和引用的动态类型和静态类型可能会不一致,但是对象的动态类型和静态类型是一致的。
D D;
D.DoSomething()和D.vfun()永远调用的都是D::DoSomething()和D::vfun()。

至于那些事动态绑定,那些事静态绑定,有篇文章总结的非常好:
我总结了一句话:只有虚函数才使用的是动态绑定,其他的全部是静态绑定。目前我还没有发现不适用这句话的,如果有错误,希望你可以指出来。

特别需要注意的地方
当缺省参数和虚函数一起出现的时候情况有点复杂,极易出错。我们知道,虚函数是动态绑定的,但是为了执行效率,缺省参数是静态绑定的。
view plaincopy to clipboardprint?
class B  
{  
 virtual void vfun(int i = 10);  
}  
class D : public B  
{  
 virtual void vfun(int i = 20);  
}  
D* pD = new D();  
B* pB = pD;  
pD->vfun();  
pB->vfun(); 
class B
{
 virtual void vfun(int i = 10);
}
class D : public B
{
 virtual void vfun(int i = 20);
}
D* pD = new D();
B* pB = pD;
pD->vfun();
pB->vfun();
 
有上面的分析可知pD->vfun()和pB->vfun()调用都是函数D::vfun(),但是他们的缺省参数是多少?
分析一下,缺省参数是静态绑定的,pD->vfun()时,pD的静态类型是D*,所以它的缺省参数应该是20;同理,pB->vfun()的缺省参数应该是10。编写代码验证了一下,正确。
对于这个特性,估计没有人会喜欢。所以,永远记住:
“绝不重新定义继承而来的缺省参数(Never redefine function’s inherited default parameters value.)”

关于c++语言
目前我基本上都是在c++的子集“面向对象编程”下工作,对于更复杂的知识了解的还不是很多。即便如此,到目前为止编程时需要注意的东西已经很多,而且后面可能还会继续增多,这也许是很多人反对c++的原因。
c++是Google的四大官方语言之一。但是Google近几年确推出了go语言,而且定位是和c/c++相似。考虑这种情况,我认为可能是Google的程序员们深感c++的复杂,所以想开发一种c++的替代语言。有时间要了解一下go语言,看它在类似c++的问题上时如何取舍的。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/chgaowei/archive/2011/05/17/6427731.aspx

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/255117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

增量值编码器、单圈绝对值编码器、多圈绝对值编码器

主流的伺服电机位置反馈元件包括增量值编码器,单圈绝对值编码器,多圈绝对值编码器,旋转变压器等。下面分别介绍: 增量值编码器增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用…

永磁交流伺服电机的工作原理与更换新编码器后的常规零位校正方法

http://wuhuotun.blog.163.com/blog/static/73085450200910655748516/ 永磁交流伺服电机的编码器相位为何要与转子磁极相位对齐 其唯一目的就是要达成矢量控制的目标,使d轴励磁分量和q轴出力分量解耦,令永磁交流伺服电机定子绕组产生的电磁场始终正交于…

理解Java中字符流与字节流的区别

1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列。和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序列的对象被称为输入…

2018/03/25

2019独角兽企业重金招聘Python工程师标准>>> March 25 2018 Sunday Weather:cloudy 1、需求: a0.5 b3 ca*b 求c的值: [rootDasoncheng sbin]# cat a.sh #!/bin/bash a0.5 b3 cecho $a*$b |bc echo $canswer referred:…

elasticsearch分词聚合查询demo

2019独角兽企业重金招聘Python工程师标准>>> 我们在通过elasticsearch查询text类型的字段时,我们使用aggs进行聚合某个text类型field。这时elasticsearch会自动进行分词将分词后的结果进行聚合。获取每一个分词出现在文档的文档个数。注意:是…

Spring实战第七章

一、SpringMVC配置代替方案 1自定DispatcherServlet 按照AbstractAnnotationConfigDispatcherServletInitializer的定义,它会创建DispatcherServlet和ContextLoaderListener。 AbstractAnnotationConfigDispatcherServletInitializer有三个方法是必须要重载的abstra…

C++多线程(一)

C多线程&#xff08;一&#xff09; WIN 多线程API一 简单实例比较简单的代码&#xff0c;创建10个线程&#xff0c;其中使第4个线程在一创建就挂起&#xff0c;等到其他的线程执行的差不多的时候再使第4个线程恢复执行。#include <stdio.h>#include <stdlib.h>#i…

天梯赛2016-L2

L2-001. 紧急救援 作为一个城市的应急救援队伍的负责人&#xff0c;你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候&#xff0c;你…

伺服系统控制网络的重要性! 现场总线的重要性! SSCNET运动控制系统与发展趋势

引言&#xff1a;在2010年的时候&#xff0c;在北京的一个数控公司工作。产品采用的是通过运动控制卡发脉冲的方式&#xff0c;控制机床的X、Y、Z轴进行加工。 机床在加工产品的时候&#xff0c;一直存在着精度的问题&#xff0c;例如DMG的机床可以达到0.01的加工精度&#x…

EPSON 自带CCD图像处理包使用举例

EPSON 机器人可以购买CCD图像处理包选项&#xff0c;CCD图像处理包与SPEL语言高度结合&#xff0c;可以非常快的将项目投入应用&#xff0c;举例说明CCD图像处理包与SPEL的联合使用。 EPSON 以视觉序列定义图像处理的一个项目&#xff0c;视觉序列是一组按照特定顺序排列的视觉…

索引使用原则

前两篇文章我总结了一些SQL数据库索引的问题&#xff0c;这篇主要来分析下索引的优缼点&#xff0c;以及如何正确使用索引。 索引的优点&#xff1a;这个显而易见&#xff0c;正确的索引会大大提高数据查询&#xff0c;对结果进行排序、分组的操作效率。 索引的缺点…

挂马方式研究、挂马检测技术研究

1. 挂马定义 所谓的挂马&#xff0c;就是黑客通过各种手段&#xff0c;包括SQL注入&#xff0c;网站敏感文件扫描&#xff0c;服务器漏洞&#xff0c;网站程序0day, 等各种方法获得网站管理员账号&#xff0c;然后登陆网站后台&#xff0c;通过数据库"备份/恢复"或者…

大幅面多相机高精度定位及测量解决方案

随着机器视觉应用的日益广泛&#xff0c;大幅面多相机视觉系统的需求越来越多&#xff0c;主要应用方向为大幅面高精度的定位与测量和场景拼接等。多相机视觉系统的难点在于多相机坐标系的统一&#xff0c;可以分为两类&#xff0c;一是相机视野间无重叠部分&#xff0c;二是相…

Hadoop 使用FileSystem API 读取数据

代码&#xff1a; package com.hadoop;import java.io.IOException; import java.io.InputStream; import java.net.URI;import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.…

庖丁解牛TLD(一)——开篇

最近在网上多次看到有关Zdenek Kalal的TLD的文章&#xff0c;说他做的工作如何的帅&#xff0c;看了一下TLD的视频&#xff0c;感觉确实做的很好&#xff0c;有人夸张的说他这个系统可以和Kniect媲美&#xff0c;我倒是两者的工作可比性不大&#xff0c;实现的方法也不同。但这…

服务器性能测试

浅谈服务器性能测试的全生命周期——从测试、结果分析到优化策略 原创 2016-06-16 Micheal 腾讯WeTest测试开发者的共同关注&#xff01;作者&#xff1a;Micheal&#xff0c;腾讯资深后台开发工程师。WeTest导读 服务器性能测试是一项非常重要而且必要的工作&#xff0c;本文是…

庖丁解牛TLD(三)——算法初始化

上一讲我提到对于算法的初始化工作主要是在tldInit这个函数里实现的。主要分为如下几大步骤&#xff0c;1&#xff09;初始化Detector。2&#xff09;初始化Trajectory。3&#xff09;训练Detector 1)初始化Detector 其中bb_scan为扫描grid区域&#xff0c;该函数输入为boundin…

在未启动程序情况 点击视图设计器 弹出未将对象引用窗体的解决方案

请问下 在未运行程序情况 点击视图设计器 弹出未将对象引用窗体 解决方案&#xff1a;1.看后台进程是不是相关的进程在启动&#xff0c;如果有关闭进程&#xff1b;重启vs,即可2.重启电脑转载于:https://www.cnblogs.com/yang12311/p/5593838.html

ASP站点无法访问怎么办

确保启用了目录浏览功能 转载于:https://www.cnblogs.com/acetaohai123/p/6571257.html

五、案例-指令参考-freemarker指令、表达式

案例-指令参考描述&#xff1a;本人自己测试写了一遍&#xff0c;如有错的地方&#xff0c;懂freemarker的朋友望指点指点&#xff01; 案例-指令参考 表达式 一、 Assign 1、<#assign name1"北京" name2"上海" name3"广东"> 调用&#xf…