多态
多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
下面的实例中,基类 Shape 被派生为两个类,如下所示:

#include <iostream>
using namespace std; class Shape {
protected:
int width, height;
public:
Shape( int a=, int b=)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return ;
}
};
class Rectangle: public Shape{
public:
Rectangle( int a=, int b=):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape{
public:
Triangle( int a=, int b=):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / );
}
};
// 程序的主函数
int main( )
{
Shape *shape;
Rectangle rec(,);
Triangle tri(,); // 存储矩形的地址
shape = &rec;
// 调用矩形的求面积函数 area
shape->area(); // 存储三角形的地址
shape = &tri;
// 调用三角形的求面积函数 area
shape->area(); return ;
}

编译输出:

kevin@kevin-virtual-machine:~/Documents/Test/C++/eight$ ./
Parent class area :
Parent class area :

导致错误输出的原因是,调用函数 area() 被编译器设置为基类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。

但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示:

class Shape {
protected:
int width, height;
public:
Shape( int a=, int b=)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return ;
}
};

修改后,编译输出:

kevin@kevin-virtual-machine:~/Documents/Test/C++/eight$ ./
Rectangle class area :
Triangle class area :

此时,编译器看的是指针的内容,而不是它的类型。因此,由于 tri 和 rec 类的对象的地址存储在 *shape 中,所以会调用各自的 area() 函数。
正如您所看到的,每个子类都有一个函数 area() 的独立实现。这就是多态的一般使用方式。有了多态,您可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。

虚函数

虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。

纯虚函数

您可能想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。
我们可以把基类中的虚函数 area() 改写如下:

class Shape {
protected:
int width, height;
public:
Shape( int a=, int b=)
{
width = a;
height = b;
}
// pure virtual function
virtual int area() = ;
};

= 0 告诉编译器,函数没有主体,上面的虚函数是纯虚函数。

C++解析八-多态的更多相关文章

  1. ReactiveSwift源码解析(八) SignalProducer的代码的基本实现

    在前面几篇博客中我们详细的聊了ReactiveSwift中的Bag.Event.Observer以及Signal的使用方式和代码实现.那么在接下来的这几篇博客中,我们就依附于之前博客的基础上来聊一聊S ...

  2. Celery 源码解析八:State 和 Result

    在前面几篇解析中,我们已经看过了 Worker 是如何运行的,Task 是如何创建的,以及怎么被路由到 Worker 中,除了这些之外,我们还对流量限制,Worker 控制和 Task/Worker ...

  3. C++基础学习教程(七)----类编写及类的两个特性解析---&gt;多态&amp;继承

    类引入 到眼下为止我们所写的自己定义类型都是keywordstruct,从如今起我们将採用class方式定义类,这样的方式对于学习过其它高级语言包含脚本(Such as Python)的人来说再熟悉只 ...

  4. jQuery 源码解析(八) 异步队列模块 Callbacks 回调函数详解

    异步队列用于实现异步任务和回调函数的解耦,为ajax模块.队列模块.ready事件提供基础功能,包含三个部分:Query.Callbacks(flags).jQuery.Deferred(funct) ...

  5. 《MySQL数据分析实战》八句箴言前四句解析

    大家好,我是jacky朱元禄,很高兴继续跟大家学习<MySQL数据分析实战>,从本节课程开始,jacky将从SQL语句入手,给大家解析八句箴言: 不管三七二十一,先把数据show来看: 数 ...

  6. 20172325 2017-2018-2 《Java程序设计》第八周学习总结

    20172325 2017-2018-2 <Java程序设计>第八周学习总结 教材学习内容总结 1.关于绑定 绑定:在执行程序时产生一个请求事件,需要执行一段代码来来完成方法调用,即一个方 ...

  7. QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数

    QT源码解析(一) QT创建窗口程序.消息循环和WinMain函数 分类: QT2009-10-28 13:33 17695人阅读 评论(13) 收藏 举报 qtapplicationwindowse ...

  8. Celery 源码解析三: Task 对象的实现

    Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...

  9. Celery 源码解析五: 远程控制管理

    今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...

随机推荐

  1. python_字符串的格式化输出

    name = input("Name:")age = int(input("Age:")) input: 输入的内容默认为字符串格式job = input(&q ...

  2. Python WebSocket长连接心跳与短连接

    python websocket 安装 pip install websocket-client 先来看一下,长连接调用方式: ws = websocket.WebSocketApp("ws ...

  3. tensorflow 的数据管理

    tensorflow api操纵和管理的是numpy矩阵数据 例子: import tensorflow as tf import numpy as np vector_np = np.array([ ...

  4. Zookeeper应用之——队列(Queue)

    为了在Zookeeper中实现分布式队列,首先需要设计一个znode来存放数据,这个节点叫做队列节点,我们的例子中这个节点是/zookeeper/queue. 生产者向队列中存放数据,每一个消息都是队 ...

  5. dygod.net

    # -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.sp ...

  6. winfrom进程、线程、用户控件

    一.进程 一个进程就是一个程序,利用进程可以在一个程序中打开另一个程序. 1.开启某个进程Process.Start("文件缩写名"); 注意:Process要解析命名空间. 2. ...

  7. scanperiod 不生效

    注意:要改 target 目录下的,真正运行时加载的 logback-spring.xml

  8. [转载]Oracle Golden Gate - 概念和机制 (ogg)

    出处:https://www.cnblogs.com/qiumingcheng/p/5435907.html Golden Gate(简称OGG)提供异构环境下交易数据的实时捕捉.变换.投递. OGG ...

  9. Docker Registry V2 Garbage Collection

    运行 docker run --rm -v /nfs1/docker/registry:/var/lib/registry registry:2.5.1 garbage-collect -d /roo ...

  10. 虚拟机下Linux安装jdk

    1.利用共享文件夹复制本地硬盘下(H:/share)的压缩包到指定目录 cp jdk-8u161-linux-x64.tar.gz /soft/jdk 2.进入/soft/jdk目录下,解压jdk到当 ...