当前位置:  编程技术>c/c++/嵌入式

C++中虚函数与纯虚函数的用法

    来源: 互联网  发布时间:2014-10-27

    本文导语:  本文较为深入的分析了C++中虚函数与纯虚函数的用法,对于学习和掌握面向对象程序设计来说是至关重要的。具体内容如下: 首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象、继承、动态绑定。通过数...

本文较为深入的分析了C++中虚函数与纯虚函数的用法,对于学习和掌握面向对象程序设计来说是至关重要的。具体内容如下:

首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象、继承、动态绑定。通过数据抽象,可以使类的接口与实现分离,使用继承,可以更容易地定义与其他类相似但不完全相同的新类,使用动态绑定,可以在一定程度上忽略相似类的区别,而以统一的方式使用它们的对象。

虚函数的作用是实现多态性(Polymorphism),多态性是将接口与实现进行分离,采用共同的方法,但因个体差异而采用不同的策略。纯虚函数则是一种特殊的虚函数。虚函数联系到多态,多态联系到继承。所以本文中都是在继承层次上做文章。没了继承,什么都没得谈。

一、虚函数

1 . 定义

在C++中,基类必须将它的两种成员函数区分开来:一种是基类希望其派生类进行覆盖的函数;另一种是基类希望派生类直接继承而不要改变的函数。对于前者,基类通过在函数之前加上virtual关键字将其定义为虚函数(virtual)。

class Base{ // 基类 
public: 
  virtual int func(int n) const; 
}; 
 
class Derive_Class : public Base{ 
public: 
  int func(int n) const; // 默认也为虚函数 
}; 

当我们在派生类中覆盖某个函数时,可以在函数前加virtual关键字。然而这不是必须的,因为一旦某个函数被声明成虚函数,则所有派生类中它都是虚函数。任何构造函数之外的非静态函数都可以是虚函数。派生类经常(但不总是)覆盖它继承的虚函数,如果派生类没有覆盖其基类中某个虚函数,则该虚函数的行为类似于其他的普通成员,派生类会直接继承其在基类中的版本。

2 . 动态绑定

当我们使用基类的引用(或指针)调用一个虚函数时将发生动态绑定(dynamic binding)。因为我们直到运行时才能知道到底调用了哪个版本的虚函数,可能是基类中的版本也可能是派生类中的版本,判断的依据是引用(或指针)所绑定的对象的真实类型。与非虚函数在编译时绑定不同,虚函数是在运行时选择函数的版本,所以动态绑定也叫运行时绑定(run-time binding)。

3 . 静态类型与动态类型

静态类型指的是变量声明时的类型或表达式生成的类型,它在编译时总是已知的;动态类型指的是变量或表达式表示的内存中的对象的类型,它直到运行时才可知。当且仅当通过基类的指针或引用调用虚函数时,才会在运行时解析该调用,也只有在这种情况下对象的动态类型才有可能与静态类型不同。如果表达式既不是引用也不是指针,则它的动态类型永远与静态类型一致。

4 . final和override

派生类中如果定义了一个函数与基类中虚函数同名但形参列表不同,编译器会认为这是派生类新定义的函数。如果我们的意图本是覆盖虚函数,则这种错误很难发现。通过在派生类中的虚函数最后加override关键字使得意图更加清晰。如果我们使用override标记了某个函数,但该函数并没有覆盖已存在的虚函数,编译器将报错。

class Base{ // 基类 
public: 
  virtual int func(int a, int b) const; 
}; 
 
class Derive_Class : public Base{ 
public: 
  int func(int a) const override; // 报错,没有覆盖虚函数 
}; 

如果我们定义一个类,并不希望它被继承。或者希望某个函数不被覆盖,则可以把类或者函数指定为final,则之后任何尝试继承该类或覆盖该函数的操作将引发错误。

class Base final { /*  */ };   // 基类不能被继承 
class Derive_Class : public Base { /* */ };   // 报错 
 
void func(int) const final;  // 不允许后续的其他类覆盖func(int)

5 . 回避虚函数的机制

在某些情况下,我们希望对虚函数的调用不要进行动态绑定,而是强迫其执行虚函数的某个特定版本。可以使用作用域运算符实现这一目的。

// 强行调用基类中定义的函数版本而不管baseP的动态类型是什么 
int a = baseP->Base::func(42); 

如果一个派生类虚函数需要调用它的基类版本,但是没有使用作用域运算符,则在运行时该调用将被解析为对派生类版本自身的调用,从而导致无限递归。

二、纯虚函数

1 . 定义

为了方便使用多态特性,我们常常需要在基类中定义虚函数。在许多情况下,在基类中不能对虚函数给出有意义的实现。为了让虚函数在基类什么也不做,引进了“纯虚函数”的概念,使函数无须定义。我们通过在函数体的位置(即在声明语句的分号之前)书写=0就可以将一个虚函数说明为纯虚函数(pure virtual)。其中,=0只能出现在类内部的虚函数声明语句处:

class Base{ // 抽象基类 
public: 
  virtual int func(int n) const =0; 
}; 

需要注意的是,我们也可以为纯虚函数提供定义,不过函数体必须定义在类的外部。

2 . 抽象基类

含有(或者未经覆盖直接继承)纯虚函数的类叫抽象基类(abstract base class)。抽象基类负责定义接口,而后续的其他类可以覆盖该接口。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象基类。因为抽象基类含有纯虚函数(没有定义),所以我们不能创建一个抽象基类的对象,但可以声明指向抽象基类的指针或引用。

Base base;  // 错误,不能实例化抽象基类 

总结:

①.虚函数必须实现,不实现编译器会报错。

②.父类和子类都有各自的虚函数版本。由多态方式在运行时动态绑定。

③.通过作用域运算符可以强行调用指定的虚函数版本。

④.纯虚函数声明如下:virtual void funtion()=0; 纯虚函数无需定义。包含纯虚函数的类是抽象基类,抽象基类不能创建对象,但可以声明指向抽象基类的指针或引用。

⑤.派生类实现了纯虚函数以后,该纯虚函数在派生类中就变成了虚函数,其子类可以再对该函数进行覆盖。

⑥.析构函数通常应该是虚函数,这样就能确保在析构时调用正确的析构函数版本。


    
 
 

您可能感兴趣的文章:

  • C++ Maps 成员 key_comp():返回比较元素key的函数
  • 怎么样在C++里调用Fortran函数??????
  • C++ Maps 成员 value_comp():返回比较元素value的函数
  • SOS ,在UNIX下编译C++程序时出现链接错误:未下义的符号,但函数库里有这些函数,不知道为什么?
  • C++ MultiMaps 成员 key_comp():返回比较key的函数
  • 求linux C++的时间相关函数及用法,急用,谢谢
  • C++ MultiMaps 成员 value_comp():返回比较元素value的函数
  • C++ 函数编程库 FC++
  • C++ Strings(字符串) 成员 Constructors:构造函数,用于字符串初始化
  • linux iis7站长之家
  • Linux c++虚函数(virtual function)简单用法示例代码
  • C++中虚拟函数表的问题
  • C++ STL Bitsets构造函数及成员函数解释及代码示例
  • linux下编译c++程序,系统头文件中包含的函数的定义源代码可以查看吗?
  • c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例
  • Linux中的共享库难道只能导出函数,而不能导出C++类吗?
  • c++断言assert()函数的头文件及其用法详解
  • 常用C++函数库 Libretta
  • Windows和Linux下C++类成员方法作为线程函数方法介绍
  • C++空类默认函数详细解析
  • C++ STL库中priority_queue介绍,成员函数说明及priority_queue具体用法举例
  • 如何在C程序中调用C++中的函数
  • PHP的substr() 函数用法
  • 浅谈SQLServer的ISNULL函数与Mysql的IFNULL函数用法详解
  • php中检测变量是否是一个对象的is_object函数介绍及用法举例
  • 请教semop()函数的用法、含义
  • linux c malloc函数定义及用法详解
  • oracle中lpad函数的用法详解
  • c/c++ assert()函数用法及其头文件
  • getdate()函数的用法实例
  • Linux下C语言strstr()查找子字符串位置函数详细介绍(strstr原型、实现及用法)
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • linux c 生成随机数srand函数和rand函数介绍及代码示例
  • 请问:定义了2个函数,其中第一个函数要访问另外一个函数的变量,怎么处理阿?谢谢
  • Linux下gettimeofday()函数和clock()函数:精确到毫秒级的时间
  • 如果知道一个函数的地址或函数名,如何得到函数所在的文件名?
  • sharepoint 2010 使用STSNavigate函数实现文件下载举例
  • java的数学函数在那个类中,如幂函数、指数、对数、双曲线函数等?
  • cityhash 32位,64位和128位介绍及函数列表
  • 一个父类的构造函数的参数是(Applet applet),请问它的子类构造函数当中应怎样调用父类构造函数?
  • linux c下利用srand和rand函数生成随机字符串
  • 虚函数被类的构造析构函数和成员函数调用虚函数的执行过程
  • Python类的构造函数,析构函数以及垃圾回收机制详细介绍及代码举例
  • 在内核的某个函数中,如何能知道是哪个用户空间的函数调用了它,以及这个用户空间函数所在的文件?
  • Linux下c基于openssl生成MD5的函数
  • 在dos下访问内存的MK_FP函数在linux下对应什么函数?int86()函数呢?
  • Linux下c函数dlopen实现加载动态库so文件代码举例
  • 一个静态库包含多个函数,应用程序连接了库中的某个函数,应用程序目标代码中是否还包含了该静态库中的其他函数代码?
  • Linux Kernel 'sctp_v6_xmit()'函数信息泄露漏洞
  • Oracle 函数大全[字符串函数,数学函数,日期函数]第1/4页
  • 哈希函数的构造方法及举例
  • js的众多函数令小弟实在搞不清楚!哪有函数速查手册之类的软件或者书籍!谢了!比如,setInterval、clearInterval这两个函数是干什么的?
  • libpcap工作原理及抓包主要函数介绍
  • 虚函数与纯虚函数(C++与Java虚函数的区别)的深入分析


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3