C++中的虚函数、纯虚函数区别和联系

C++中的虚函数、纯虚函数区别和联系

虚函数和纯虚函数有以下所示方面的区别。
(1)类里如果声明了虚函数,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的子类里面可以被覆盖,这样的话,这样编译器就可以使用后期绑定来达到多态了。纯虚函数只是一个接口,是个函数的声明而已,它要留到子类里去实现。
(2)虚函数在子类里面也可以不重载的;但纯虚函数必须在子类去实现,这就像Java的接口一样。通常把很多函数加上virtual,是一个好的习惯,虽然牺牲了一些性能,但是增加了面向对象的多态性,因为很难预料到父类里面的这个函数不在子类里面不去修改它的实现。
(3)虚函数的类用于“实作继承”,继承接口的同时也继承了父类的实现。当然大家也可以完成自己的实现。纯虚函数关注的是接口的统一性,实现由子类完成。
(4)带纯虚函数的类叫虚基类,这种基类不能直接生成对象,而只有被继承,并重写其虚函数后,才能使用。这样的类也叫抽象类。抽象类和大家口头常说的虚基类还是有区别的,在C#中用abstract定义抽象类,而在C++中有抽象类的概念,但是没有这个关键字。抽象类被继承后,子类可以继续是抽象类,也可以是普通类,而虚基类,是含有纯虚函数的类,它如果被继承,那么子类就必须实现虚基类里面的所有纯虚函数,其子类不能是抽象类。

纯虚函数

声明了纯虚函数的类是一个抽象类。所以,用户不能创建类的实例,只能创建它的派生类的实例。

纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(不要后面的=0,否则该派生类也不能实例化),而且它们在抽象类中往往没有定义。

定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。

纯虚函数的意义,让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你必须提供一个纯虚函数的实现,但我不知道你会怎样实现它”。

顺便说一句,为一个纯虚函数提供定义也是可能的。也就是说,你可以为纯虚函数提供实现,C++编译器也不会阻拦(DEV_CPP中G++(gcc 3.4.2)编译器并不支持为纯虚函数定义缺省行为;在VC6.0支持为纯虚函数定义缺省的实现,派生类的虚函数override基类的纯虚函数),但调用它的唯一方式是通过类名完整地指明是哪个调用(如:pb->Base:: pureVirtual())。

有时,声明一个除纯虚函数外什么也不包含的类很有用。这样的类叫协议类(Protocol class),它为派生类仅提供函数接口,完全没有实现。

虚函数(在此指的是非纯虚函数)

虚函数的情况和纯虚函数有点不一样。照例,派生类继承了函数的接口,但简单虚函数一般还提供了实现,派生类可以选择改写(override)它们或不改写它们。

声明虚函数的目的在于,使派生类继承函数的接口和缺省实现。

虚函数的意义,每个类必须提供一个可以被调用的虚函数,但每个类可以按它们认为合适的任何方式处理。如果某个类不想做什么特别的事,可以借助于基类中提供的缺省处理函数。也就是说,虚函数的声明是在告诉子类的设计者,”你必须支持虚函数,但如果你不想写自己的版本,可以借助基类中的缺省版本。”

实际上,为虚函数同时提供函数声明和缺省实现是很危险的。(当你增加一个派生类继承基类时,必须小心使用虚函数,满足派生类特有的需求,否则就是调用基类的虚函数,可能引起错误)

非虚函数

最后,来谈谈类的非虚函数,当一个成员函数为非虚函数时,它在派生类中的行为就不应该不同。实际上,非虚成员函数表明了一种特殊性上的不变性,因为它表示的是不会改变的行为――不管一个派生类有多特殊。

声明非虚函数的目的在于,使派生类继承函数的接口和强制性实现。(所有的派生类都应该完成的使用该函数完成某一个功能)

建议

结合前面的学过的,再次强调一下,如果你没有为类设计虚函数(纯虚函数),该类一般来说应该不具有继承特性(除非确实的存在IS-A关系,即便存在,派生类也没有了特殊性,这种情况一般是设计中抽象的不合理)。当然除了Protocol class也不应该把类的成员函数全部设计成虚函数(纯虚函数),这也说明了类设计的不合理(不能正确的抽象出基类、派生类之间不变的部分)。

c++中没有接口的概念,与之对应的是纯虚类,即只含有纯虚函数的类,c++抽象类的概念是含有纯虚函数成员的类。这是因为c++提供多继承,而像 java、c#这些只提供单继承(避免多继承的复杂性和低效性)的语言为了模拟多继承功能就提供了接口概念,接口可以继承多个。

abstract class是抽象类,至少包含一个纯虚函数的类就叫做抽象类。

但是如果一个类,所有的成员都是纯虚函数,那么它和一般的抽象类在用法上是有区别的。至少Microsoft给的COM接口定义全部都是仅由纯虚函数构成的类。因此把这样的类定义叫做纯虚类也不算错。

纯虚函数和虚函数的区别在于前者不包含定义,而后者包含函数体。

那么纯虚类就是不包含任何实现(包括成员函数定义和成员变量定义。前者代表算法,后者代表结构)。不包含任何算法和结构的类叫做纯虚类,应该没有问题。

在Java里面的确没有纯虚类的概念,因为Java里没有纯虚函数这个概念。Java管虚函数叫做abstract function,管抽象类叫做abstract class,直接说来,Java根本没有virtual这个关键字,都用abstract代替,因此Java里面根本就没有Pure这个概念。有那就是 interface。在interface里面定义的函数都不能有函数体,这个在Java里面叫做接口。那么C++里面与interface等同的概念就 是纯虚类了,C++用纯虚类来模拟interface这个抽象概念,因此这里说的“纯虚类”与Java的abstract class不同,与C++的一般抽象类也不同。“纯虚类”与C++一般抽象类的区别就好比Java里面interface 和 abstract class的区别。

2、抽象类:

抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。

⑴抽象类的定义:

称带有纯虚函数的类为抽象类。

⑵抽象类的作用:

抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。所 以派生类实际上刻画了一组子类的操作接口的通用语义,这些语义也传给子类,子类可以具体实现这些语义,也可以再将这些语义传给自己的子类。

(3)使用抽象类时注意:

• 抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。

• 抽象类是不能定义对象的。

abstract不是c++的关键词,是微软自己的发明,用来提供.net支持 。VC++并不规范,笔者用devcpp做程序设计,无abstract关键字
至于抽象类确实一个类中有纯虚函数就是抽象类 。CSDN中关于C++中abstract关键字的介绍应该是微软扩展出来的,编译器不支持abstract关键字。

没有更多推荐了,返回首页