多态也是C++中的一个重要的方面。多态和动态类型,虚函数本质上是指同样的事情。





1 虚函数

类中的成员函数原型前面加上virtual 表面这个函数是个虚函数。虚函数的目的是为了在继承它的派生类中又一次定义这个函数,以便于通过基类的指针或引用在执行时对派生类的函数进行调用。

2 派生类和虚函数

派生类普通情况下要重定义所继承的虚函数。有几个注意事项。

<1>虚函数的声明必须和基类中的函数声明原型全然一致。例外的是当基类返回基类型的指针或者引用的时候。派生类能够派生类类型的指针或者引用

<2>virtual 关键词加不加无所谓,可是一般要加上,能看的清楚这是个虚函数

<3>virtual的标签一旦在基类中的函数前面加上。就永远也去不掉





3 动态绑定的触发

C++的函数调用默认不使用动态绑定。使用动态绑定须要两个必须的条件

<1>通过基类类型的指针或者引用进行函数的调用

<2>函数是虚函数

通过这里也能够说明,当通过指针或者引用调用函数的时候,即便派生类重定义了基类的版本号。也不会调用派生类的版本号。由于它不会触发多态。

4 虚函数的覆盖机制

有时候通过指针或者引用不想触发多态。此时能够通过加限定符来显式的调用基类的函数

Derived d;
Base *p = &d;
p->Base::func();

假设在派生类中的函数定义的时候想要调用基类的同名函数那么也要这样显式的调用,否则会引发无穷递归。





5 虚函数跟复制控制

<1>通常将析构函数设置为虚函数,这是由于析构函数在运行的时候仅仅会运行自身的部分。

比如通过基类的指针或者引用来调用析构函数的话,那么仅仅会调用基类的构造函数。派生类的构造函数将不会被调用。

<2>构造函数不能定义为虚函数,由于在构造函数是在对象全然构造之前执行的。在构造函数执行的时候,对象的动态类型还不完整。

<3>赋值操作符原理上能够设置为虚函数。可是这样做是没意义的。原因例如以下:

虚函数要求函数原型全然一致,这当中包含了函数參数类型的一致,假设我们把operator = 设置为虚函数。那么在基类中函数的參数是基类类型,在派生类虚函数的參数类型依旧是基类类型。可是赋值操作符是要求函数參数类型和类类型一致。这样就会产生很easy混淆的东西。

class Base{
public:
virtual Base& operator =(Base& xx);
} class Derived : public Base
{
public:
virtual Derived& operator =(Base& xx); //virtual function
Derived& operator =(Derived& xx); //real operator =
}

6 构造函数和析构函数中的虚函数

在执行构造函数和析构函数的时候。此时的对象都不是一个完整的类。这个时候编译器将对象的对象视作在构造期间发生了变化,假设在当中调用虚函数的话。那么调用的将会是类自身类型





定义的版本号。

原因:基类在构造的时候,派生类部分的成员还没有初始化,假设此时调用的是派生类的虚函数,那么派生类的虚函数訪问类成员就会出问题。

同理基类的析构函数也是这样子。由于析构函





数直管自身成员的释放,派生类在调用析构函数的时候先调用自身的析构函数。然后再去调用基类的析构函数。所以基类的析构函数不可能调用派生类的虚函数,由于派生类的成员已经被释





放。实比例如以下:

//Base.h
#pragma once
#include <iostream>
using namespace std; class Base
{
public:
Base(void){ func();};
~Base(void){ funp();};
virtual void func(){cout<<"this is in Base constructor"<<endl;}
virtual void funp(){cout<<"this is in Base destructor"<<endl;};
};
//Derived.h
#pragma once
#include "base.h"
class Derived :
public Base
{
public:
Derived(void){func();}
~Derived(void){func();}
virtual void func(){cout<<"this is in Derived constructor"<<endl;}
virtual void funp(){cout<<"this is in Derived destructor"<<endl;};
};
//main.cpp
#include "Derived.h" void main()
{
Base X;
Derived Y;
}

7 纯虚函数

虚函数的形參后面跟上“=0”则表示纯虚函数。纯虚函数须要注意的有下面几点:

<1>纯虚函数没有函数体;

<2>最后面的“=0”并不表示函数返回值为0,它仅仅起形式上的作用。告诉编译系统“这是纯虚函数”;

<3>这是一个声明语句,最后应有分号。

<4>函数不能被调用

<5>不能创建有纯虚函数的类对象

<6>假设在一个类中声明了纯虚函数,而在其派生类中没有对该函数定义。则该虚函数在派生类中仍然为纯虚函数。





含有一个或者多个纯虚函数的类被称为抽象类。抽象类不能创建对象。抽象类的意义在于提供功能基础接口。然后由派生类来实现,在此基础上实现多态。可是抽象类能够作为引用或者指针。

实例程序例如以下:

//Base.h
#pragma once
#include <iostream>
using namespace std; class Base
{
public:
Base(void){ func();};
~Base(void){ funp();};
virtual void func(){cout<<"this is in Base constructor"<<endl;}
virtual void funp(){cout<<"this is in Base destructor"<<endl;};
virtual void fuck()=0;
};
//Derived.h
#pragma once
#include "base.h"
class Derived :
public Base
{
public:
Derived(void){func();}
~Derived(void){func();}
virtual void func(){cout<<"this is in Derived constructor"<<endl;}
virtual void funp(){cout<<"this is in Derived destructor"<<endl;};
virtual void fuck(){cout<<"what a fuck day it is!"<<endl;}
};

//main.cpp
#include "Derived.h" void main()
{
Derived Y;
Base& X = Y;
}

C++primer读书笔记11-多态的更多相关文章

  1. 机器学习实战 - 读书笔记(11) - 使用Apriori算法进行关联分析

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第11章 - 使用Apriori算法进行关联分析. 基本概念 关联分析(associat ...

  2. 强化学习读书笔记 - 11 - off-policy的近似方法

    强化学习读书笔记 - 11 - off-policy的近似方法 学习笔记: Reinforcement Learning: An Introduction, Richard S. Sutton and ...

  3. Key Technologies Primer 读书笔记,翻译 --- Struct 学习 1

    原文链接:https://struts.apache.org/primer.html 本来想写成读书笔记的,结果还是变成翻译,谨作记录,学习.   1.HTML -- 见我前面文章 2.Interne ...

  4. 《精通Spring 4.X企业应用开发实战》读书笔记1-1(IoC容器和Bean)

    很长一段时间关注在Java Web开发的方向上,提及到Jave Web开发就绕不开Spring全家桶系列,使用面向百度,谷歌的编程方法能够完成大部分的工作.但是这种不系统的了解总觉得自己的知识有所欠缺 ...

  5. c++ primer 读书笔记

    顺序容器:为程序提供控制元素存储和访问顺序的能力,这种顺序与元素加入到容器时的位置相对应,而与元素值无关. 另外还有根据关键字的值来存储元素的容器:有序.无序关联容器. 另外STL还有三种容器适配器, ...

  6. c++ primer读书笔记之c++11(四)

    1  带有作用域的枚举 scoped-enumeration 相信大家都用过枚举量,都是不带有作用域的,在头文件中定义需要特别注意不要出现重名的情况.为了解决这种问题,c++11提供了带作用于的枚举. ...

  7. c++ primer读书笔记之c++11(三)

    1 =default构造函数限定符 c++11针对构造函数提供了=default限定符,可以用于显式指定编译器自动生成特定的构造函数.析构或赋值运算函数.参考代码如下: class CtorDftTy ...

  8. c++ primer读书笔记之c++11(二)

    1 新的STL模板类型,std::initializer_list<T> c++11添加了initializer_list模板类型,用于提供参数是同类型情况的可变长度的参数传递机制,头文件 ...

  9. c++ primer读书笔记之c++11(一)

    1 新的关键词nullptr c++11引入新的关键词nullptr,用于表示空指针,用于替换之前c提供的NULL(最初NULL是定义在stdlib中的宏定义,通常是0). 2 新的别名定义机制 al ...

  10. C++ Primer 读书笔记:第11章 泛型算法

    第11章 泛型算法 1.概述 泛型算法依赖于迭代器,而不是依赖容器,需要指定作用的区间,即[开始,结束),表示的区间,如上所示 此外还需要元素是可比的,如果元素本身是不可比的,那么可以自己定义比较函数 ...

随机推荐

  1. iText操作pdf(生成,导入图片等)

    生成pdf有很多种方法,用pdfbox也很方便,今天我要写的是用iText 主要在pom.xml中配置的jar包如下 <dependency> <groupId>com.low ...

  2. 【Codeforces Round #476 (Div. 2) [Thanks, Telegram!] D】Single-use Stones

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 设长度为L的所有区间里面,石头的个数的最小值为k 设取到k的区间为l,r 那么k就为最多能通过的青蛙个数. 假设k再大一点.比如为k ...

  3. 2015 Multi-University Training Contest 3 hdu 5324 Boring Class

    Boring Class Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  4. POJ——T2421 Constructing Roads

    http://poj.org/problem?id=2421 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 24132   ...

  5. HDU 4336

    概率DP期望,逆推即可.使用状态压缩. 注意,要全部输出...看DIS才发现题目输出是个坑.. #include <iostream> #include <cstdio> #i ...

  6. IIS身份验证的配置

    前4者配置:localhost applicationHost.config <location path=""> 后2者配置:web.config 要点: 这6项尽管 ...

  7. Java5新特性之枚举

    1.  概念 首先,枚举并非一种新技术,而是一种基础数据类型.它隶属于两种基础类型中的值类型,例如以下: 2.  为什么要有枚举 枚举在真正的开发中是非经常常使用的,它的作用非常easy也非常纯粹:它 ...

  8. (八)统一配置中心-Config

    对于配置的重要性,我想我不用进行任何强调,大家都可以明白其重要性.在普通单体应用,我们常使用配置文件(application(*).properties(yml))管理应用的所有配置.这些配置文件在单 ...

  9. Codeforces 659F Polycarp and Hay 并查集

    链接 Codeforces 659F Polycarp and Hay 题意 一个矩阵,减小一些数字的大小使得构成一个连通块的和恰好等于k,要求连通块中至少保持一个不变 思路 将数值从小到大排序,按顺 ...

  10. sql server 更新满足条件的某一条记录

    上图数据:SNum为”18004XXXXX000001K2GW 4000 L1C“,OffLineStation为“OP1010”的有两条数据,当where条件中为上述两者时会同时更新这两条数据,并不 ...