什么是多态?

多态(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 介绍+动态绑定、静态绑定的更多相关文章

  1. 深入理解OOP(三):多态和继承(动态绑定和运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...

  2. 《编程导论(Java)&#183;2.1.2 啊,我看到了多态》-什么是多态(polymorphism)

    1.不明觉厉 很多人学习多态时,会认为. 之所以不明觉厉,由于多态的定义:事物存在的多种表现形态:而后,有人将重载(overload).改写(override).多态变量和泛型归结于同一个术语&quo ...

  3. java之多态(Polymorphic)、动态绑定(Dynamic Binding)、迟绑定(Late Binding)

    今天,我们来说说java面向对象最核心的东西,多态.通过多态可以使我们的程序可复用性达到极致,这就是我们为什么要学多态的原因. “多态”(Polymorphic)也叫“动态绑定”(Dynamic Bi ...

  4. 7.6 GRASP原则六: 多态 Polymorphism

    GRASP原则六: 多态 Polymorphism  How to handle alternative behaviors based on type 如何处理依据类型不同而有 不同行为的一类需求 ...

  5. AJPFX关于多态中的动态绑定和静态绑定的总结

    在多态中:成员变量和静态方法编译和运行都看左边:成员方法编译看左边,运行看右边,这是为什么:在Java中存在两种绑定方式,一种为静态绑定,又称作早期绑定.另一种就是动态绑定,亦称为后期绑定1.静态绑定 ...

  6. 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 运行时多态或迟绑定.动态绑定 在C#语音中,运行时 ...

  7. java面向对象之 多态 Polymorphism

    多态(Polymorphism):用我们通俗易懂的话来说就是子类就是父类(猫是动物,学生也是人),因此多态的意思就是:父类型的引用可以指向子类的对象. 1.多态的含义:一种类型,呈现出多种状态 主要讨 ...

  8. obj-c编程05:类的多态与id动态绑定

    说实在的,写这第5篇的时候十分纠结,代码老是不能动态绑定,在编译时就会出错,最后发现这是开了ARC的原因.开了ARC obj-c就不能动态绑定了吗?这个问题还不清楚哦.把ARC关闭后,虽然会有警告,但 ...

  9. 多态(Polymorphism)的实现机制

    1. 我理解的广义的 override 是指抛开各种访问权限,子类重定义(redefine)父类的函数(即函数签名相同). 2. C++中的三个所谓的原则:never redefine base cl ...

随机推荐

  1. LINE学习

    LINE Abstract LINE 是一种将大规模网络结点表征成低维向量的算法,可很方便用于网络可视化,结点分类,链路预测,推荐. source code Advantage LINE相比于其他算法 ...

  2. kubernetes备份和恢复

    kubernetes备份和恢复   备份etcd数据 首先由于ETCD有三个备份,并且会同步,所以您只需要在一台master机器上执行ETCD备份即可. 另外在运行下列命令前,确保当前机器的kube- ...

  3. Docker技术入门与实战 第二版-学习笔记-10-Docker Machine 项目-2-driver

    1>使用的driver 1〉generic 使用带有SSH的现有VM/主机创建机器. 如果你使用的是机器不直接支持的provider,或者希望导入现有主机以允许Docker Machine进行管 ...

  4. Docker技术入门与实战 第二版-学习笔记-8-网络功能network-1-单个host上的容器网络

    Docker 中的网络功能介绍 Docker 允许通过外部访问容器或容器互联的方式来提供网络服务 1) 外部访问容器 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -p或 -P参数 ...

  5. day3-课堂代码

    # a = ('哈哈', 'xixi', 'hehe') # print(a[0]) # print(a[0:2]) # # # 列表 # a = ['哈哈', 'xixi', 'hehe', 1, ...

  6. Block abstraction view(Create & Reference)

    在hierarchical design 中,一般需要调用 hard macro,top调用 macro 的方法有多种: 1. 调用macro对应的db 2. 调用 macro 的 ilm 模型(20 ...

  7. JAVA框架 Mybaits 输入和输出映射

    一.输入映射 当前端传来的参数,比较复杂,比如说用户名称.订单单号.账号信息等等.后端有可能有多个projo类对应这些信息.我们需要把这些的projo类封装成一个类似一个vo类. 通过设置字段形式关联 ...

  8. flask 入门(二)

    Windows(提前安好virtualenv:pip  install  virtualenv) 一.准备: 1.启动pycharm 2.创建flask项目 二.基本库安装和设置 1.创建沙盒virt ...

  9. 添加静态路由 route add -host 子网掩码 -- 在线解析

    1.215        -----       R(172.16.0.1)      <--------- gw(61.146.164.109) |                       ...

  10. 串口通信DMA中断

    这是以前学32的时候写的,那时候学了32之后感觉32真是太强大了,比51强的没影.关于dma网上有许多的资料,亲们搜搜,这里只贴代码了,其实我也想详详细细地叙述一番,但是自己本身打字就慢,还有好多事情 ...