在基类中加入Virtual关键字的函数就是虚拟函数,在基类的派生类中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。当基类的指针指向派生类的对象时,对指针虚拟函数的调用实际上是调用了派生类的虚拟函数。这是面向对象中多态性的体现。
例子:
class A
{
public:
virtual void foo()
{
cout<<"A::foo() is called"<<endl;
}
};
class B:public A
{
public:
void foo()
{
cout<<"B::foo() is called"<<endl;
}
};
int main(void)
{
A *a = new B();
a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
return 0;
}
这个例子是虚函数的一个典型应用。虚函数的虚是在所谓的“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被称为“虚”函数。
虚函数只能借助于指针或者引用来达到多态的效果。
************
纯虚函数
***********
1、定义
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但是要求任何派生类都要定义自己的实现方方法。在基类中实现纯虚函数的方法是在函数原型后面加“=0”,如:
virtual void funtion1()=0
2、引入原因
(1)为了方便使用多态特性,我们常常需要在基类中定义虚拟函数
(2)在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。
纯虚函数的引入很好的解决了上述问题,将声明了纯虚函数的类称为抽象类,它不能生成对象,即用户不能创建类的实例,只能创建它的派生类的实例。
3、特征:
纯虚函数最显著的特征是:它们必须在继承类中重新声明函数(后面就不要在加0啦,否则该派生类也不能实例化),而且他们在抽象类中往往没有定义。
4、目的
定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。让所有的派生类对象都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。
所以类纯虚函数的声明就是在告诉子类的设计者:“你必须提供一个纯虚函数的实现,但是我不造你会怎样实现它”。
来个例子吧,方便以后理解:
Header.h
#include <iostream>
// 公共抽象基类Vehicle
class Vehicle
{
public:
//声明为纯虚函数
virtual void run() const = 0;
//在很多多态的例子中都可以看到将基类的方法声明为纯虚函数,
//这样可以要求子类必须实现这个方法,同时体现面向接口编程
};
// 派生于Vehicle的具体类Car
class Car : public Vehicle
{
public:
virtual void run() const
{
std::cout << "run a car\n";
}
};
// 派生于Vehicle的具体类Airplane
class Airplane : public Vehicle
{
public:
virtual void run() const
{
std::cout << "run a airplane\n";
}
};
source.cpp
// source.cpp
#include "stdafx.h"
#include <iostream>
#include "Header.h"
// 通过指针run任何vehicle
void run_vehicle(const Vehicle* vehicle)
{
vehicle->run(); // 根据vehicle的具体类型调用对应的run()
}
int main()
{
Car car;
Airplane airplane;
run_vehicle(&car); // 调用Car::run()
run_vehicle(&airplane); // 调用Airplane::run()
}
结果:
***************************************************************************
补充:(参考维基百科)
在C++语言中, 纯虚函数可用一种特别的语法定义 ,见以下示例:
class Abstract {
public:
virtual void pure_virtual() = 0;
};
抽象类中实现的调用可以采用以下这种形式:
void Abstract::pure_virtual() {
// do something
}
class Child : public Abstract {
virtual void pure_virtual(); // no longer abstract, this class may be
// instantiated.
};
void Child::pure_virtual() {
Abstract::pure_virtual(); // the implementation in the abstract class
// is executed
}
举一个例子作为结束:
抽象基类"MathSymbol"可能提供一个纯虚函数 doOperation(), 派生类 "Plus" 和 "Minus" 提供doOperation() 的具体实现. 由于 "MathSymbol" 是一个抽象概念, 为其每个子类定义了同一的动作, 在 "MathSymbol" 类中执行 doOperation() 没有任何意义. 类似的, 一个给定的 "MathSymbol" 子类如果没有 doOperation() 的具体实现是不完全的.