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++继承与虚函数机制

转载请注明出处。 这是这本书中关于逆向C++的唯一一篇总结,前面的基础知识由于去年已经学习过了钱林松老师的《C++反汇编与逆向分析技术》并做了笔记所以就只是看了一下,发现内容大同小异,不过看过一遍之...

C++ Primer Plus学习笔记之虚函数

C++ Primer Plus学习笔记之虚函数 C++语言的多态性有两种类型:静态多态性和动态多态性。函数重载和运算符重载就是静态多态性的具体表现,而动态多态性是指程序运行过程中才动态的确定操作所...

C++虚函数和多态学习笔记

  • 2007年08月31日 13:31
  • 37KB
  • 下载

C++中虚函数的实现机制

  • 2011年10月27日 13:33
  • 112KB
  • 下载

C++ Primer学习笔记——$14 操作符重载、函数对象及类类型转换

题记:本系列学习笔记(C++ Primer学习笔记)主要目的是讨论一些容易被大家忽略或者容易形成错误认识的内容。只适合于有了一定的C++基础的读者(至少学完一本C++教程)。  作者: tyc611,...
  • whycold
  • whycold
  • 2011年01月19日 15:09
  • 724

C++学习笔记53——纯虚函数与继承中的容器

1,纯虚函数 (1)定义方式:在虚函数的形参表后用“=0”声明,例如: class Base4 { public: Base4(int ii, int jj) :i(ii), j(jj) { c...

c++ 虚函数的实现机制:笔记

1、c++实现多态的方法 其实很多人都知道,虚函数在c++中的实现机制就是用虚表和虚指针,但是具体是怎样的呢?从more effecive c++其中一篇文章里面可以知道:是每个类用了一个虚表,...

c++ 虚函数的实现机制:笔记

1、c++实现多态的方法 其实很多人都知道,虚函数在c++中的实现机制就是用虚表和虚指针,但是具体是怎样的呢?从more effecive c++其中一篇文章里面可以知道:是每个类用了一个虚表,...

【好文章】c++ 虚函数的实现机制:笔记

1、c++实现多态的方法 其实很多人都知道,虚函数在c++中的实现机制就是用虚表和虚指针,但是具体是怎样的呢?从more effecive c++其中一篇文章里面可以知道:是每个类用了一个虚表,...
  • lenchio
  • lenchio
  • 2011年12月02日 15:35
  • 415

C++虚函数学习笔记(仅供参考)

1、虚函数的作用: 允许在派生类中重新定义与基类同名的函数,并且可以通过基类的指针或引用来访问基类和派生类中的同名函数。 2、虚函数的工作原理 编译器处理虚函数的方法:对每个对象添加一个隐藏成员...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ Primer学习笔记(14)——虚函数的实现机制、纯虚函数
举报原因:
原因补充:

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