1.C++中的多态

(1)多态性:同一个函数的调用能够进行不同的操作,函数重载是实现多态的一种手段。

(2)联编:在编译阶段进行联接。即是在编译阶段将一个函数的调用点和函数的定义点联接起来。

A.静态联编:在编译阶段就完毕的函数联编——函数重载。

B.动态联编:在程序的执行阶段由系统自己主动选择详细的函数——虚函数。

注:C++的多态主要指的就是动态联编。

2.虚函数

(1)虚函数是在函数的定义时将其声明为虚函数就可以。

(2)说明:virtual 数据类型 函数名(參数表) {函数体}

A.目的:当通过基类指针调用虚函数时,系统进行动态联编。

B.在派生类中定义了和基类名称同样、參数个数同样、參数类型同样、返回值类型同样的函数时。若基类中的同名成员函数是虚函数,派生类的同名成员函数将自己主动被虚化。

C.通过对象訪问虚函数时採用静态联编。

动态联编仅仅可以通过指向对象的指针和对象的引用来完毕。

3.样例

example 1



#include <iostream.h>



class Point(

{

private:

    float x, y;

public:

    void setpoint(float i, float j)

    {

        x = i; y = j;

    }

    float area() {return 0.0;}//等价于:float area()=0;

};

const float PI=3.1416;

class Circle:pulic Point

{

private:

    float rad;

public:

    void setrad(float r) {rad = r;}

    float area() {return PI*rad*rad;}

};

int main()

{

    Point p;

    Circle c;

    float a = p.area();

    cout<<a<<endl;

    c.setrad(2.5);

    a = c.area();

    cout<<a<<endl;

}

分析:

float a=p.area()调用的是Point类的area函数:p是基类Point的对象;对象调用函数时採用静态联编;Point类的对象调用area,area一定是Point类的area;a=c.area()调用的是Circle类的area函数,由于就近原则。

改动main函数:



int main()

{

    Point *p;

    Circle c;

    float a;

    c.setrad(2.5);

    p = &c;

    a = p->area();//该函数属于静态联编

    cout<<a<<endl;

}

程序输出:

0.0

分析:虽然基类指针指向了派生类对象,但仅仅可以通过基类的指针引用派生类对象从基类继承过去的成员。假设要想基类指针可以指向派生类的成员,那么就要使用虚函数,从而实现动态联编。

4.四种静态联编

(1)基类指针指向基类对象,採用静态联编调用基类成员。

(2)派生类的指针指向派生类的对象採用静态联编,调用派生类成员。若派生类没有的成员。调用基类的该成员。

(3)基类指针指向派生类对象,採用静态联编,调用基类成员。

(4)对象引用成员一定是静态联编。基类对象引用基类成员,派生类对象引用派生类成员,若派生类没有则能够引用基类成员。

注:派生类指针不可指向基类,引用也不能够。

5.动态联编

(1)条件:基类的同名函数被声明为虚函数。基类指针指向派生类对象。

(2)作用:使用动态联编。使得一个基类指针能够訪问多个派生类的成员函数,动态联编仅仅能通过指针或引用来实现(前提是虚函数机制)。

example 2



#include <iostream.h>



class Point

{

public:

    virtual double area() {return 0.0;}

};

class Rectangle:public Point

{

    double length, width;

public:

    Rectangle(double l, double w):length(l), width(w) {}

    double area() {return length*width;}

};

class Circle:public Point

{

    double radium;

public:

    Circle(double r) {radium = r;}

    double area() {return 3.1416*radium*radium;}

};

class Triangle:public Point

{

    double x, y, z;

public:

    Triangle(double a, double b, double c)

    {x = a; y = b; z = c;}

    double area() {return (x+y+z)*0.5;}

};

int main()

{

    Point *p;

    Rectangle r(5.0, 2.0);

    Circle c(6.0);

    Triangle t(3.0, 4.0, 5.0);

    p = &r;

    cout<<p->area()<<endl;

    p = &c;

    cout<<p->area()<<endl;

    p = &t;

    cout<<p->area()<<endl;

}

程序输出:

10

113.098

6

注:基类的虚函数也能够被调用。调用方法:加类的作用域(强制採用静态联编)。

演示样例:

p = &r;

p->area();//调用Rectangle类的area函数

p->Point::area();//强制採用静态联编,调用Point类作用下的area函数

6.虚函数的訪问权限

(1)派生类中的虚函数不影响动态联编,基类的虚函数是保证动态联编的必要条件。

(2)一个类中的虚函数仅仅对派生类重定义的函数有影响,对它的基类成员无影响。

example 3



#include <iostream.h>



class A

{

public:

    virtual void fun1()

    {cout<<"fun1()...fun2()"<<endl; fun2();}

    void fun2()

    {cout<<"fun2()...fun3()"<<endl; fun3();}

    virtual void fun3()

    {cout<<"fun3()...fun4()"<<endl; fun4();}

    virtual void fun4()

    {cout<<"fun4()...fun5()"<<endl; fun5();}

    void fun5() {cout<<"The end."<<endl;}

};

class B:public A

{

    void fun3()

    {cout<<"fun3...fun4"<<endl; fun4();}

    void fun4()

    {cout<<"fun4...fun5"<<endl; fun5();}

    void fun5()

    {cout<<"All done."<<endl;}

};

int main()

{

    A *thing;

    thing = new A;

    thing->fun1();

    thing = new B;

    thing->fun1();

}

程序输出:

fun1()...fun2()

fun2()...fun3()

fun3()...fun4()

fun4()...fun5()

The end.

fun1()...fun2()

fun2()...fun3()

fun3...fun4

fun4...fun5

All done.

7.若基类和派生类中的同名函数參数个数不同。參数类型不同,基类中的成员函数虽然是虚函数。但将丢失虚特性——採用静态联编。

基类和派生类中的同名成员函数,若出现基类中的同名成员函数非虚,派生类中同名成员函数是虚函数。那么也将採用静态联编。

example 4



#include <iostream.h>



class Base

{

public:

    virtual void fun1() {cout<<"Base fun1."<<endl;}

    virtual void fun2() {cout<<"Base fun2."<<endl;}

    void fun3() {cout<<"Base fun3."<<endl;}

    void fun4() {cout<<"Base fun4."<<endl;}

};

class Device:public Base

{

public:

    virtual void fun1()

    {cout<<"Device fun1."<<endl;}

    virtual void fun2()

    {cout<<"Device fun2."<<endl;}

    virtual void fun3()

    {cout<<"Device fun3."<<endl;}

    virtual void fun4()

    {cout<<"Device fun4."<<endl;}

};

int main()

{

    Base *pb;

    Device d;

    pb = &d;

    pb->fun1();

    pb->fun2();

    pb->fun3();

    pb->fun4();

}

程序输出:

Device fun1.

Device fun2.

Base fun3.

Base fun4.

C++语言笔记系列之十八——虚函数(1)的更多相关文章

  1. C++语言笔记系列之十二——C++的继承

    C++的继承 1.继承方式 public(公有继承) 派生类中的成员能够訪问基类的public成员和protected成员,但不能訪问基类的private成员. 派生类的对象仅仅能訪问基类的publi ...

  2. C++语言笔记系列之十六——赋值兼容规则&amp;多继承的二义性

    1.赋值兼容规则 (1)派生类对象能够给基类对象赋值,这样的情况下派生类对象将从基类继承的成员的值赋值给一个基类对象:可是不同意将一个基类的对象赋值给一个派生类. (2)能够将派生类对象的地址赋给基类 ...

  3. C++语言笔记系列之十——静态成员

    1.静态成员 (1)由keywordstatic修饰 静态变量定义语句在编译阶段就运行,运行过程中不再运行. (2)分类:静态数据成员.静态成员函数. (3)静态成员时类的全部对象共享的成员,而不是某 ...

  4. Web 前端开发人员和设计师必读文章推荐【系列二十八】

    <Web 前端开发精华文章推荐>2014年第7期(总第28期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  5. OSGi 系列(十八)之 基于注解的 Blueprint

    OSGi 系列(十八)之 基于注解的 Blueprint 1. 注解实现 blueprint 第一步:bundle 添加 Bundle-Blueprint-Annotation <plugin& ...

  6. Java 设计模式系列(十八)备忘录模式(Memento)

    Java 设计模式系列(十八)备忘录模式(Memento) 备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式.备忘录对象是一个用来存储另外一个对象内部状态 ...

  7. 【Java学习笔记之二十八】深入了解Java8新特性

    前言: Java8 已经发布很久了,很多报道表明java8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java 8 ...

  8. ComicEnhancerPro 系列教程十八:JPG文件长度与质量

    作者:马健邮箱:stronghorse_mj@hotmail.com 主页:http://www.comicer.com/stronghorse/ 发布:2017.07.23 教程十八:JPG文件长度 ...

  9. Dynamic CRM 2013学习笔记(二十八)用JS动态设置字段的change事件、必填、禁用以及可见

    我们知道通过界面设置字段的change事件,是否是必填,是否可见非常容易.但有时我们需要动态地根据某些条件来设置,这时有需要通过js来动态地控制了. 下面分别介绍如何用js来动态设置.   一.动态设 ...

随机推荐

  1. VMware虚拟机无法识别U盘解决方式

    1. 本机情况: Winxp操作系统(相同应该适用于win7),VMware虚拟机.虚拟机版本号:VMware 10.安装Ubuntu14.04.现要求在主机上插入U盘.在虚拟机中显示. 2. 遇到问 ...

  2. Spring Data MongoDB 五:进阶文档查询(分页、Morphia)(二)

    Spring Data MongoDB 三:基本文档查询(Query.BasicQuery)(一) 学习MongoDB 六: MongoDB查询(游标操作.游标信息)(三) 一.简单介绍 Spring ...

  3. jQuery取得循环列表的第一列值

    有例如以下的表格: <table class="list_tab" id="personalDetail"> <tr class=" ...

  4. UVALive 3027 Corporative Network 带权并查集

                         Corporative Network A very big corporation is developing its corporative networ ...

  5. Swift - 判断是否有某功能访问权限,没有则提示,并自动跳转到设置页

    由于 iOS 系统的安全限制,App 如果需要访问设备的通讯录.麦克风. 相册. 相机.地理位置等时,需要请求用户是否允许访问.   有时用户不小心点了“不允许”,后面可能就不知道要去哪里再开启这个权 ...

  6. POJ 3260 DP

    只需要对John的付款数做一次多重背包,对shopkeeper的找零钱数做一次完全背包即可. 最重要的是上界的处理.可以注意到,John的付款数最多为maxv*maxv+m,也就是24400元.同理, ...

  7. MongoDB在MacOS上的客户端Robo 3T 的简单使用(二)

    最近写了一个用node来操作MongoDB完成增.删.改.查.排序.分页功能的示例,并且已经放在了服务器上地址:http://39.105.32.180:3333. 本篇文章只做简单介绍,能够使用起来 ...

  8. c# rc4算法,加密解密类

    rc4算法,原理,以密匙生成256位的密匙流,然后以车轮式滚过源数据异或加密. /* * 由SharpDevelop创建. * 用户: YISH * 日期: 04/04/2015 * 时间: 03:0 ...

  9. Excel基础视频教程在线观看

    也许你已经在Excel中完成过上百张财务报表,也许你已利用Excel函数实现过上千次的复杂运算,也许你认为Excel也不过如此,甚至了无新意.但我们平日里无数次重复的得心应手的使用方法只不过是Exce ...

  10. Ubuntu下快速配置Caffe

    Caffe安装 实际上在windows上安装过多次caffe了,无论是BLVC版本的还是Microsoft版本的,ubuntu的按照也进行过,这段时间在自己笔记本上 又折腾了下caffe安装,发现其实 ...