虚函数
程序示例
例如,一个基类 Animal 有一个虚函数 eat。子类 Fish 要实做一个函数 eat(),这个子类 Fish 与子类 Wolf 是完全不同的,但是你可以引用类别 Animal 底下的函数 eat() 定义,而使用子类 Fish 底下函数 eat() 的进程。
C++
以下代码是 C++ 的程序示例。要注意的是,这个示例没有异常处理的代码。尤其是 new 或是 vector::push_back 丢出一个异常时,程序在运行时有可能会出现当掉或是错误的现象。
类别 Animal 的区块图
# include # include usingnamespacestd;classAnimal{public:virtualvoideat()const{cout<<"I eat like a generic Animal."<<endl;}virtual~Animal(){}};classWolf:publicAnimal{public:voideat()const{cout<<"I eat like a wolf!"<<endl;}};classFish:publicAnimal{public:voideat()const{cout<<"I eat like a fish!"<<endl;}};classGoldFish:publicFish{public:voideat()const{cout<<"I eat like a goldfish!"<<endl;}};classOtherAnimal:publicAnimal{};intmain(){std::vectoranimals;animals.push_back(newAnimal());animals.push_back(newWolf());animals.push_back(newFish());animals.push_back(newGoldFish());animals.push_back(newOtherAnimal());for(std::vector::const_iteratorit=animals.begin();it!=animals.end();++it){(*it)->eat();delete*it;}return0;}
以下是虚函数 Animal::eat() 的输出:
当 Animal::eat() 不是被宣告为虚函数时,输出如下所示:
Java
在Java语言中, 所有的方法默认都是"虚函数". 只有以关键字 final 标记的方法才是非虚函数. 以下是 Java 中虚方法的一个例子:
importjava.util.*;publicclassAnimal{publicvoideat(){System.out.println("I eat like a generic Animal.");}publicstaticvoidmain(String[]args){Listanimals=newLinkedList();animals.add(newAnimal());animals.add(newWolf());animals.add(newFish());animals.add(newOtherAnimal());for(AnimalcurrentAnimal:animals){currentAnimal.eat();}}}publicclassWolfextendsAnimal{publicvoideat(){System.out.println("I eat like a wolf!");}}publicclassFishextendsAnimal{publicvoideat(){System.out.println("I eat like a fish!");}}publicclassOtherAnimalextendsAnimal{}
输出:
C#
在 C# 语言中, 对基类中的任何虚方法必须用 virtual 修饰, 而派生类中由基类继承而来的重载方法必须用 override 修饰. 一下是 C# 的一个程序实例:
usingSystem;usingSystem.Collections.Generic;namespaceConsoleApplication1{publicclassAnimal{publicvirtualvoidEat(){Console.WriteLine("I eat like a generic Animal.");}}publicclassWolf:Animal{publicoverridevoidEat(){Console.WriteLine("I eat like a wolf!");}}publicclassFish:Animal{publicoverridevoidEat(){Console.WriteLine("I eat like a fish!");}}publicclassGoldFish:Fish{publicoverridevoidEat(){Console.WriteLine("I eat like a goldfish!");}}publicclassOtherAnimal:Animal{// Eat() method is not overridden, so the base class method will be used.}publicclassProgram{publicstaticvoidMain(string[]args){IListanimals=newList();animals.Add(newAnimal());animals.Add(newWolf());animals.Add(newFish());animals.Add(newGoldFish());animals.Add(newOtherAnimal());foreach(AnimalcurrentAnimalinanimals){currentAnimal.Eat();}}}}
输出:
抽象类和纯虚函数
纯虚函数或纯虚方法是一个需要被非抽象的派生类覆盖(override)的虚函数. 包含纯虚方法的类被称作抽象类; 抽象类不能被直接实例化。 一个抽象基类的一个子类只有在所有的纯虚函数在该类(或其父类)内给出实现时, 才能直接实例化. 纯虚方法通常只有声明(签名)而没有定义(实现),但有特例情形要求纯虚函数必须给出函数体定义.
作为一个例子, 抽象基类"MathSymbol"可能提供一个纯虚函数 doOperation(), 和派生类 "Plus" 和 "Minus" 提供doOperation() 的具体实现. 由于 "MathSymbol" 是一个抽象概念, 为其每个子类定义了同一的动作, 在 "MathSymbol" 类中执行 doOperation() 没有任何意义. 类似的, 一个给定的 "MathSymbol" 子类如果没有 doOperation() 的具体实现是不完全的.
虽然纯虚方法通常在定义它的类中没有实现, 在 C++ 语言中, 允许纯虚函数在定义它的类中包含其实现, 这为派生类提供了备用或默认的行为. C++的虚基类的虚析构函数必须提供函数体定义,否则链接时(linking)在析构该抽象类的派生实例对象的语句处会报错。
C++
在C++语言中, 纯虚函数用一种特别的语法[=0]定义(但 VS 也支持 abstract 关键字:virtual ReturnType Function()abstract;), 见以下示例.
classAbstract{public:virtualvoidpure_virtual()=0;};
纯虚函数的定义仅提供方法的原型. 虽然在抽象类中通常不提供纯虚函数的实现, 但是抽象类中可以包含其实现, 而且可以不在声明的同时给出定义. 每个非抽象子类仍然需要重载该方法, 抽象类中实现的调用可以采用以下这种形式:
voidAbstract::pure_virtual(){// do something}classChild:publicAbstract{virtualvoidpure_virtual();// no longer abstract, this class may be// instantiated.};voidChild::pure_virtual(){Abstract::pure_virtual();// the implementation in the abstract class // is executed}
参考文献
C++ FAQ LiteCopyright © 1991-2006, Marshall Cline.
免责声明:以上内容版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。感谢每一位辛勤著写的作者,感谢每一位的分享。
- 有价值
- 一般般
- 没价值