C++ 中的虚:虚函数和纯虚函数
一、多态形成的基本条件
(1)静多态:即函数重载。表面上看,是由重载规则来限定的,内部实现却是Name mangling(命名倾轧 )行为,发生在编译期,故称静多态。
(2)(动)多态:在运行阶段决定,故称动多态。
形成条件如下:
以下面画图操作为例子:
①父类中有虚函数,即共用接口。(由声明型关键字virtual修饰的函数)
class Shape
{
public:
Shape(int x=0,int y=0)
:x_(x),y_(y)
{}
virtual void draw()
{
cout << "draw shape from point(" << x_ << "," << y_ << ")" << endl;
}
protected:
int x_;
int y_;
};
②子类覆写父类中的虚函数。(子类中对应的函数要满足:同名、同参、同返回才能构成覆写)
class Circle:public Shape
{
public:
Circle(int x = 0, int y = 0,int r=0)
:Shape(x,y)
{
r_ = r;
}
virtual void draw()
{
cout << "draw circle from point(" << x_ << "," << y_ << ")" <<"and r="<<r_<< endl;
}
protected:
int r_;
};
class Rect :public Shape
{
public:
Rect(int x = 0, int y = 0, int w = 0,int h=0)
:Shape(x, y)
{
w_ = w;
h_ = h;
}
virtual void draw()
{
cout << "draw rect from point(" << x_ << "," << y_ << ")"
<< "and w=" << w_ <<" h="<<h_<< endl;
}
protected:
int w_;
int h_;
};
③通过已被子类对象赋值的父类指针,调用共用接口,形成多态。
int main()
{
Circle c(10,20,4);
Shape *ps = &c;
ps->draw();
Rect r(13, 2,10,6);
ps = &r;
ps->draw();
return 0;
}
完整例子:
#include<iostream>
using namespace std;
class Shape
{
public:
Shape(int x=0,int y=0)
:x_(x),y_(y)
{}
virtual void draw()
{
cout << "draw shape from point(" << x_ << "," << y_ << ")" << endl;
}
protected:
int x_;
int y_;
};
class Circle:public Shape
{
public:
Circle(int x = 0, int y = 0,int r=0)
:Shape(x,y)
{
r_ = r;
}
virtual void draw()//这里的virtual可也不写
{
cout << "draw circle from point(" << x_ << "," << y_ << ")" <<"and r="<<r_<< endl;
}
protected:
int r_;
};
class Rect :public Shape
{
public:
Rect(int x = 0, int y = 0, int w = 0,int h=0)
:Shape(x, y)
{
w_ = w;
h_ = h;
}
virtual void draw() override //c++11提供了关键字override,给覆写指定了此关键字。加override表明从父类中覆写了draw(),这里的override可以不加
{
cout << "draw rect from point(" << x_ << "," << y_ << ")"
<< "and w=" << w_ <<" h="<<h_<< endl;
}
protected:
int w_;
int h_;
};
int main()
{
Circle c(10,20,4);
Shape *ps = &c;
ps->draw();
Rect r(13, 2,10,6);
ps = &r;
ps->draw();
return 0;
}
二、抽象基类
上面的例子可以看到,Shape类中的函数成员draw()并没有用到,可以不要函数的实现体,而且一般也不会用Shape这个类去实例化对象。
class Shape
{
public:
Shape(int x=0,int y=0)
:x_(x),y_(y)
{}
virtual void draw() = 0;
protected:
int x_;
int y_;
};
此时这个类就叫抽象基类。
抽象基类: 含有纯虚函数的类,称为抽象基类,且该类不能实例化,存在的意义就是被继承,提供族类的公共接口。
三、总结
虚函数:被virtual修饰的成员函数。是形成多态的基本条件。
纯虚函数:被virtual修饰,且只有声明,没有实现体,被“初始化”为0的成员函数。只有纯接口类,才配具备拥有纯虚函数。