C++ Primer学习笔记(14)——虚函数的实现机制、纯虚函数

原创 2015年07月08日 20:46:30

在行文之前查阅了相关书籍,参考了一些别人的博客,在这里谢谢大家的分享!希望自己和大家在学习语言的道路上渐行渐远,一直走下去~~~

上一篇文章中说道,C++ 的三个基本特质是 封装、继承、多态。

多态性是将接口与实现进行分离。用形象的语言解释就是实现已共同的方法,但因个体差异而采用不同的策略。

多态包括静多态和动多态,分别在编译和运行过程中实现。而动多态是由虚函数来实现的,其实现机制体现了C++的神秘性。

1.虚函数的实现机制

虚函数是那些以 virtual 关键字修饰的成员函数,是用来实现多态的。

两个重要的关键词揭示了它的神秘面纱 : 虚表、虚指针。每个类用了一个虚表,每个类对象用了一个虚指针。

具体演示如下:

class A
{
public:
    virtual void f();
    virtual void g();
private:
    int a;
};

class B : public A
{
public:
    void g();   // 覆盖父类A中的虚函数g()
private:
    int b; 
};

因为 A 有 virtual void f( ) ,和 g( ),所以编译器为 A 类准备了一个虚表 vtableA,内容如下:

这里写图片描述

B 继承了A,所以里面也有继承于A的虚函数,故B也有一个虚表vtableB:
这里写图片描述

PS:因为B:: g是重写了的,所以B的虚表的g放的是B::g的入口地址,而f 还是A:: g 的入口地址。

当执行B bt; 定义类对象的时候,编译器分配空间时,除了 A 的int a 成员 , B的 int b 成员,还分配了指向B的虚表vtableB 的指针vptr , 对象bt 的布局如下:

这里写图片描述

其中,虚表指针总是在最前面的。

当执行下面的语句时:

A *pa = &bt;  //一个A 类型的指针,指向B类型的对象bt

pa ->g( ) 实际上是由 指针vptr指向B的虚表vtableB,然后去里面寻找g()函数。可以看到,vtableB里面是 B:: g( ),即B 自己的g( ),而不是A 的g( )。
这就是多态。

总结:

要知道 虚函数实现多态的机制,谨记虚表、虚指针。能够列出父类和子类的虚表,以及子类对象的虚指针,就不难理解这个机制了。

2. 纯虚函数(pure virtual function)

很多时候,定义一个类的对象是没有意义的,例如,动物这个类,由它可以派生出大象、狮子、猴子等子类,但动物本身生成对象是没有实际意义的。为了解决这个问题,提出了纯虚函数的概念。
假如定义的虚函数为:

virtual void animals(string& name, int age){}

那么如下就是纯虚函数:

virtual void animals(string& name, int age) = 0;   // 函数体直接为0 的虚函数

存在纯虚函数的类称为 抽象类,是一个单纯地接口,抽象类本身实例化,即不能生成对象,只能也必须在派生类中去实例化。

什么情况下使用纯虚函数呢?

  • 当想在基类中抽象出一种方法,且该基类只能被继承,不能实例化

  • 这个方法必须在派生类中实现

针对上述两点分别举例说明:

1) 抽象类不能实例化

例如:定义一个形状的类(Cshape),但凡是形状我们都要求能显示自己,所以定义一个类如下:

class Cshape
{
    virtual show(){}
};

我们不想将这个类实例化,首先会想到将show( )这个函数的函数体 { } 删除,改为 virtual show( );

这时如果尝试实例化 Cshape shape; 这样其实是能够通过编译的,只能在连接的时候报错。

那么如何能够在编译的时候就报错呢?

~~用纯虚函数:

class Cshape
{
    virtual show() = 0// 纯虚函数不能实例化
};

2) 该方法必须在派生类中实现

如上面的例子,show( ) 必须在每一个子类中实现,即在子类中重新定义自己的 show( ) 函数,若没有定义,编译时就会报错:

// 定义Cshape 的派生类,忘了定义show()
class CPoint : public Cshape
{  
public:
    void msg()
    {
        cout << " 这是一个点。" << endl;
    }
private:
    float x;
    float y;
};

// 下面实例化 CPoint 类的时候就会报错!!!
CPoint point1;

在编译的时候就会报错!!!

~~~~
这是不是一个预防在派生类中实现基类的方法? (^__^)

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++ Primer中文本查询示例Query的实现

最近在看C++ Primer复习C++的语法,看到书中15.9章中的文本查询示例时,觉得设计得非常不错,于是便动手照着实现了一个,修改了很久终于运行成功了,从中也学习到了很多的语法。下面把实现与总结分...
  • zhaoxy2850
  • zhaoxy2850
  • 2014年07月20日 19:12
  • 2183

《C++ Primer》真的适合入门吗?

客气地说,《C++ Primer》不适合大学C++基础课堂教学,也不适合初学者入门。 不客气地说,恐怕你们的大学老师也搞不定《C++ Primer》,更别说拿这本书教学生了。 更不客气地说...
  • qq_23291783
  • qq_23291783
  • 2015年12月22日 16:32
  • 960

如何学习C++ primer 第五版

作者:dawnmist 链接:http://www.zhihu.com/question/32087709/answer/54936403 来源:知乎 著作权归作者所有,转载请联系作者获得授权。...
  • w3071206219
  • w3071206219
  • 2016年08月22日 22:03
  • 851

C++primer第14章习题解答

练习14.1:在什么情况下重载的运算符与内置运算符有所区别?在什么情况下重载的运算符又与内置运算符一样? 不同点: 重载运算符必须具有至少一个class或枚举类型的操作数。 重载运算符不保证操作数的求...
  • sunhero2010
  • sunhero2010
  • 2016年04月19日 22:07
  • 2914

C++Primer第五版——习题答案+详解(完整版)

C++Primer第五版——习题答案详解       看的也比较快,但是有很多东西确实用不上,所以很多都没有深入的探讨,但是知识点覆盖的很全面,每一道题涉及的知识点我都写上简单的解释了。      ...
  • misayaaaaa
  • misayaaaaa
  • 2016年12月21日 16:11
  • 43573

《C++ Primer》随附代码的使用方法

(Source: C++ Primer, Fifth Edition Visual Studio 2012 Code Distribution README ) Conditional Compil...
  • guohuaien
  • guohuaien
  • 2017年02月17日 13:49
  • 548

C++ Primer第四版(中文版) pdf下载

编辑推荐 《C++ Primer中文版(第4版)》对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使《C++ Primer中文版(第4版)》成为C++初学者的最佳指南;对于...
  • u012550652
  • u012550652
  • 2013年10月23日 23:08
  • 3279

如何利用《C++ Primer》学习C++?

《C++ Primer》作为久负盛名的C++经典教程,丰富的教学辅助内容、精心组织的编程示范,无论是初学者入门,或是中、高级程序员提升,都是不容置疑的首选。一本好书只有读过才有价值,然而《C++ Pr...
  • shiyanlou_chenshi
  • shiyanlou_chenshi
  • 2015年08月14日 16:00
  • 1228

C++ Primer(第五版) 学习笔记

C++语言基础: 1. C++11增加了long long 类型,表示最小尺寸为64的整数。 2. 浮点数运算使用double,通常运算速度更快。 3. 超过int容量时使用long long类型,无...
  • zxh2075
  • zxh2075
  • 2016年10月25日 15:56
  • 413

C++ Primer学习总结 第7章 类

第7章 类 1.    引入const成员函数(C++ Primer P231-232) C++类的常量对象是无法调用非const成员函数的,如果想让常量对象调用某个成员函数,必须声明...
  • u013480600
  • u013480600
  • 2015年03月07日 01:02
  • 1573
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ Primer学习笔记(14)——虚函数的实现机制、纯虚函数
举报原因:
原因补充:

(最多只允许输入30个字)