C++ 多态Polymorphism 介绍+动态绑定、静态绑定
什么是多态?
多态(polymorphism)一词最初来源于希腊语polumorphos,含义是一种物质的多种形态。
在专业术语中,多态是一种运行时绑定机制(run-time binding) ,通过这种机制,实现将函数名绑定到函数具体实现代码的目的。
多态的目的
根据赋值兼容,用基类类型的指针指向派生类,就可以通过这个指针来使用派生类的成员函数。如果这个函数是普通的成员函数,通过基类类型的指针访问到的只能是基类的同名成员。而如果将它设置为虚函数,则可以使用基类类型的指针访问到指针正在指向的派生类的同名函数。这样,通过基类类型的指针,就可以使属于不同派生类的不同对象产生不同的行为,从而实现运行过程的多态。
(“当通过指针或是引用使用派生类的一个对象时,此对象可以被当作是一个基类的对象”(但此时可能需要进行对象类型的判断))
#include <iostream>
using namespace std;
class A
{
public :
void Print( )
{
cout<<"A::Print"<<endl ;
}
};
class B:public A
{
public :
void Print( )
{
cout<<"B::Print"<<endl;
}
};
int main( )
{
A a;
B b;
A *pA = &b;//基类型的指针指向派生类
pA->Print( );
return ;
}
运行结果:
A::Print
通过指针调用成员函数只与指针类型有关,与此刻指向的对象无关。基类指针无论指向基类还是派生类对象,利用pA->Print()调用的都是基类成员函数Print()。若要调用派生类中的成员函数Print()必须通过对象来调用,或定义派生类指针实现。这种通过用户自己指定调用成员函数,在编译时根据类对象来确定调用该类成员函数的方式,是静态绑定。
若将A类中的Print( )函数声明为virtual,则此时就为动态绑定Dynamic binding
程序执行结果为:
B::Print
class A
{
public :
virtual void Print( )
{
cout<<"A::Print"<<endl ;
}
};
class B:public A
{
public :
void Print( )
{
cout<<"B::Print"<<endl;
}
};
虚函数(Virtual functions)允许程序员在基类中声明一个函数,然后在各个派生类中对其进行重定义(redefined). 编译器与装入器将保证对象及其所调用函数的正确对应。这里的 redefine 叫做 Overriding(覆盖,又称重置)。这是C++语言中唯一的一种动态绑定(Dynamic binding)机制。
要让一个函数调用表现出多态特征,必须满足哪些条件?
必须存在继承关系;
继承关系中必须有同名的虚函数,并且它们是覆盖关系(重载不行)。
存在基类的指针,通过该指针调用虚函数。
动态绑定和静态绑定
绑定是程序自身彼此关联的过程,确定程序中的操作调用与执行该操作的代码间的关系。例如把一个标示符名和一个存储地址联系在一起的过程。
用面向对象的术语讲,就是把一条消息和一个对象的方法相结合的过程。
按照绑定进行的阶段的不同,可以分为静态绑定和动态绑定两种。
1.静态绑定:绑定工作在编译连接阶段完成。
因为绑定过程是在程序开始执行之前进行的,因此也称为早期绑定或前绑定。
在编译、连接过程中,系统就可以根据类型匹配等特征确定程序中操作调用与执行该操作代码的关系,即确定了某一个同名标识到底是要调用哪一段程序代码。
C++中,除虚函数外,其他函数均是静态绑定的。
重载函数是静态绑定
普通函数重载与静态联编:
void print(char)
void print(char *)
void print(float)
void print(int)
……
print("Hello, overload!");
成员函数重载与静态联编:
class MyClass
{
public:
MyClass( );
MyClass(int i);
MyClass(char c);
};
MyClass c2();
2.动态绑定:和静态绑定相对应,绑定工作在程序运行阶段完成的。
以下面的代码说明:
class TradesPerson
{
public:
virtual void sayHi()
{
cout << "Just hi." << endl;
}
void run()
{
cout << "Base::run " << endl;
}
};
class Tinker : public TradesPerson
{
public:
virtual void sayHi()
{
cout << "Tinker." << endl;
}
void run()
{
cout << "Tinker::run " << endl;
}
};
class Tailor : public TradesPerson
{
public:
void sayHi()
{
cout << "Tailor." << endl;
}
void run()
{
cout << "Tailor::run " << endl;
}
};
int main( )
{
TradesPerson* p;
int which ;
cout << "1 == TradesPerson, 2 == Tinker, 3 == Tailor ";
cin >> which;
switch( which )
{
case :
p = new TradesPerson;
break;
case :
p = new Tinker;
break;
case :
p = new Tailor;
break;
}
p->sayHi();///动态绑定,运行结果不可知
p->run();///无virtual,不是虚函数,Base::run
delete p;
return ;
}
C++中对虚函数的限制:
虚函数只能是普通(对象)成员函数;
只有类的成员函数才能说明为虚函数,因为虚函数仅适用于有继承关系的类对象,所以普通函数不能说明为虚函数。在类的定义中前面有virtual关键字的成员函数就是虚函数。
静态成员函数不能是虚函数;
因为静态成员函数没有this指针,是不受限制于某个对象
类的构造函数不能是虚函数;
因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。
当类的虚函数在类外定义时,不能有virtual关键字。
类中的声明有virtual关键字。
析构函数可以是虚函数,且通常定义为虚函数。
虚函数动态绑定的实现原理
动态选择被执行的函数
函数调用时,跳转到函数代码的入口地址处执行。把函数入口地址作为变量,在不同情况下赋予不同的值,通过该变量调用函数,就可动态选择被执行的函数。
回顾:函数指针、指向成员函数的指针
虚表
每个多态类有一个虚表(virtual table)。虚表中有当前类的各个虚函数的入口地址。每个对象有一个指向当前类的虚表的指针(虚指针vptr)。
动态绑定的实现
构造函数中为对象的虚指针赋值,通过多态类型的指针或引用调用成员函数时,通过虚指针找到虚表,进而找到所调用的虚函数的入口地址,通过该入口地址调用虚函数。
例如:有下面两个父子类
class Base
{
public:
virtual void f();
virtual void g();
private:
int i;
};
class Derived: public Base
{
public:
virtual void f();//覆盖Base::f
virtual void h(); //新增的虚函数
private:
int j;
};

C++ 多态Polymorphism 介绍+动态绑定、静态绑定的更多相关文章
- 深入理解OOP(三):多态和继承(动态绑定和运行时多态)
在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...
- 《编程导论(Java)·2.1.2 啊,我看到了多态》-什么是多态(polymorphism)
1.不明觉厉 很多人学习多态时,会认为. 之所以不明觉厉,由于多态的定义:事物存在的多种表现形态:而后,有人将重载(overload).改写(override).多态变量和泛型归结于同一个术语&quo ...
- java之多态(Polymorphic)、动态绑定(Dynamic Binding)、迟绑定(Late Binding)
今天,我们来说说java面向对象最核心的东西,多态.通过多态可以使我们的程序可复用性达到极致,这就是我们为什么要学多态的原因. “多态”(Polymorphic)也叫“动态绑定”(Dynamic Bi ...
- 7.6 GRASP原则六: 多态 Polymorphism
GRASP原则六: 多态 Polymorphism How to handle alternative behaviors based on type 如何处理依据类型不同而有 不同行为的一类需求 ...
- AJPFX关于多态中的动态绑定和静态绑定的总结
在多态中:成员变量和静态方法编译和运行都看左边:成员方法编译看左边,运行看右边,这是为什么:在Java中存在两种绑定方式,一种为静态绑定,又称作早期绑定.另一种就是动态绑定,亦称为后期绑定1.静态绑定 ...
- 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)
在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 运行时多态或迟绑定.动态绑定 在C#语音中,运行时 ...
- java面向对象之 多态 Polymorphism
多态(Polymorphism):用我们通俗易懂的话来说就是子类就是父类(猫是动物,学生也是人),因此多态的意思就是:父类型的引用可以指向子类的对象. 1.多态的含义:一种类型,呈现出多种状态 主要讨 ...
- obj-c编程05:类的多态与id动态绑定
说实在的,写这第5篇的时候十分纠结,代码老是不能动态绑定,在编译时就会出错,最后发现这是开了ARC的原因.开了ARC obj-c就不能动态绑定了吗?这个问题还不清楚哦.把ARC关闭后,虽然会有警告,但 ...
- 多态(Polymorphism)的实现机制
1. 我理解的广义的 override 是指抛开各种访问权限,子类重定义(redefine)父类的函数(即函数签名相同). 2. C++中的三个所谓的原则:never redefine base cl ...
随机推荐
- mysql用户管理与权限
1.设置密码 set password for 用户名@localhost = password('密码'); 2.取消密码 set password for 用户名@localhost = pass ...
- 团队作业——Alpha冲刺 8/12
团队作业--Alpha冲刺 冲刺任务安排 杨光海天 今日任务:将编辑界面与其中字体设置的弹窗合并,学习Android控件交互. 明日任务:希望完成编辑界面所有接口交互的功能. 郭剑南 今日任务:使用P ...
- 百度地图POI数据爬取,突破百度地图API爬取数目“400条“的限制11。
1.POI爬取方法说明 1.1AK申请 登录百度账号,在百度地图开发者平台的API控制台申请一个服务端的ak,主要用到的是Place API.检校方式可设置成IP白名单,IP直接设置成了0.0.0.0 ...
- 请问下.net俱乐部这个组织现在还存在么?
各位好,我是北京的一名.net开发人员,一直在想有什么线下技术活动可以开拓自己的视野,扩展人脉,我知道曾经有一个.net俱乐部很活跃 可是现在我在百度上搜了下.net俱乐部的信息,已经基本找不到201 ...
- android studio 错误: InnerClass annotations are missing corresponding EnclosingMember annotations. Such InnerClass annotations are ignored
android studio 错误: InnerClass annotations are missing corresponding EnclosingMember annotations. Suc ...
- ap、map值计算
ap:所有图片某一个类 map:所有图片所有类的ap的平均 以一个score为阈值,大于score的所有框是假定正确输出的所有预测,将这些框和gt匹配(iou大于某一个阈值认为匹配成功),得到当前sc ...
- Dubbo -- 系统学习 笔记 -- 安装手册
安装手册 示例提供者安装 示例消费者安装 Zookeeper注册中心安装 Redis注册中心安装 简易注册中心安装 简易监控中心安装 管理控制台安装 推荐使用Zookeeper注册中心 你可以只运行D ...
- android 7.0拍照问题file:///storage/emulated/0/photo.jpeg exposed beyond app through ClipData.Item.getUri
Android7.0调用相机时出现新的错误: android.os.FileUriExposedException: file:///storage/emulated/0/photo.jpeg exp ...
- VS2010自行编译OpenCV2.4.4时缺少python27_d.lib的解决方法
错误 24 error LNK1104: 无法打开文件“python27_d.lib” C:\OpenCV\VS2013_64\modules\python\LINK opencv_python 编 ...
- aips初步设想
2018年5月10日星期四 目标:设计一个高并发,高性能,可扩展的现代化综合大前置机. 具备以下功能: 协议支持:http.socket.mq 报文支持:xml.json.8583 Tps:500笔/ ...