virtual----虚拟的
名符其实,virtual的用法就跟它的名字一样,表示一种虚假的东西,当然这里仅仅只看一下它其中的一种用法,虚函数。必须承认,虚函数还是很有用的,它的有用之处体现在当我们用一个成熟的基类继承产生一个派生类的时候,企图使用指向基类的一个指针去调用派生类里面的一个和基类具有相同名字的成员函数的时候。这句话读起来特别拗口,没办法它就是表达了这样一个拗口的事实,不过使用起来还是特别简单的。
我们先定义一个基类Shape,然后利用Shape这个基类public派生出Triangle类和Circle类,基类的public只有一个成员函数area(),在派生类Triangle和Circle类中仍然有一个同名的成员函数area(),area()是用来求面积的,我们知道派生类中的area()肯定和基类的area()不一样,派生类之间的area()也是各不相同,现在的问题是,如果我们只有一个指向基类的指针,但是我们企图通过指向基类的这个指针去引用我们指定的派生类的同名的成员函数怎么办?
请看实例如下:
#include <iostream>
using namespace std;
class Shape //基类Shape
{
public:
float area();
};
float Shape::area()
{
return 0.0;
}
class Triangle :public Shape //派生类Triangle
{
private:
float W;
float H;
public:
Triangle(float w,float h);
float area();
};
Triangle::Triangle(float w, float h)
{
W = w;
H = h;
}
float Triangle::area()
{
return 0.5*W*H;
}
class Circle:public Shape //派生类Circle
{
private:
float R;
public:
Circle(float r);
float area();
};
Circle::Circle(float r)
{
R = r;
}
float Circle::area()
{
return 3.14*R*R;
}
int main()
{
Triangle t(10,20);
Circle c(30);
Shape *p1 = &t;
Shape *p2 = &c;
cout << "t.area()=" << t.area() << endl;
cout << "c.area()=" << c.area() << endl;
cout << "p1->area()=" << p1->area() << endl;
cout << "p2->area()=" << p2->area() << endl;
return 0;
}
运行结果如下:
可以看到,即便是将派生类的对象的地址给了指向基类的指针,最后调用的函数依然是基类的。
所以,C++提供了一种方式,能让我们利用这个指向基类的指针调用派生类的成员函数,将程序的第7行做如下改动:
virtual float area();
再次运行,结果如下:
这便是我们想要的结果了。
也许会有疑问,为什么非要用指向基类的指针呢?我可以直接定义一个指向派生类的指针来完成我的需求啊,
Triangle *p1=&t;
Circle *p2=&c;
p1->area();
p2->area();
没错,这样是可以,但是考虑到派生类比较多的时候,会需要很多指针,这无疑是增加了麻烦。既然一个指向基类的指针可以完成不同的对象的成员函数调用,为什么还要费力不讨好的再定义多个专门的指向派生类的指针呢?所以,这方法还是很有用的。
现在回过头来再想想,virtual----虚拟的,确实有了新的体会。隐隐约约可以感觉到,基类提供的某些方法可能确实只是提供了一个框架性的东西,编程过程中大家肯定都更关注的是派生类,为什么这样说是因为派生类是我们按照自己的需求继承基类定制产生,这样看来基类提供的某种方法不需要做的太具体,相当于是你给我提供一个空,我自己根据需要自己去填就行了,至于怎么填完全是按照我自己的需求。接触过MFC的玩家都知道,微软给我们提供了一些基类,很多类都是从这基本的基类派生而来,而实用的功能基本都是派生类去实现的。