一-、温故
在前面几篇文章的介绍中,我们介绍了类的定义和继承相关内容,我们如下定义一个基类shape和两个派生类Round和Rectangle
class shape
{
public:
virtual double Area(){}
};
class Round:public shape
{
int r;
public:
const double pi=3.14;
Round(){}
Round(int r){this->r=r;}
double Area()
{
return pi*r*r;
}
};
class Rectangle:public shape
{
int width;
int height;
public:
Rectangle(int w,int h):width(w),height(h){}
double Area()
{
return width*height;
}
};
二、知新
在shape类里面我们在Area函数的前面加了一个virtual,为什么要加这个呢?
如果我们加一个全局作用下的函数
void area(shape *p)
{
cout<<p->Area()<<endl;
}
我们在编译的时候会发现输出为空。
因为上面采用的是静态联编机制,而我们需要动态联编。
静态联编是指在编译阶段就确定了函数调用与执行该函数代码间的关系;而动态联编则是指在程序运行时才确定函数调用与执行该函数代码间的关系。
静态联编又称早期联编或静态束定,在此过程中,函数调用与具体实现的关联是在编译时期就确定的。它是在程序执行前就完成的联编工作。它要求在编译阶段就能够明确程序中的操作调用(如函数调用)与执行该操作代码间的关系。
动态联编又称为晚期联编或动态束定,函数调用与函数体之间的关联在程序运行时才得以确定。它发生在程序运行时,是对虚函数的实现,通过虚函数支持多态性。
所以看到这里相信同学们已经理解了为什么需要加virtual。
此时的Area函数就被称作是“虚函数”
所以,实现多态的三个条件:
1、虚函数(就是带virtual的)
2、赋值兼容性
赋值兼容性是指在需要基类对象的地方,可以使用公有派生类的对象来代替的原则。
在面向对象编程中,继承允许一个类(派生类)继承另一个类(基类)的特性。如果派生类从基类公有继承,那么它继承了基类中除构造函数和析构函数以外的所有成员。因此,公有派生类具备了基类的所有功能,凡是基类能解决的问题,公有派生类也都能解决。
3、 通过指针或者引用调用虚函数
我们把剩下的代码补全
void getArea(shape *p)
{
cout<<p->Area()<<endl;
}
int main()
{
Round y(1);
Rectangle j(3,4);
getArea(&y);
getArea(&j);
return 0;
}
可以得到运行结果:
下面顺便提一下纯虚函数:
纯虚函数emmmmmm就是什么都没有,很虚……
比如我们定义了一个shape类的对象,shape s;
然后我们cout<<s.Area();然后发现什么输出都没有。
shape本来就是我们为了实现多态才创建的。所以对于shape里的virtual可以这样写:
virtual double Area()=0;
也是可以的。与此同时shape拥有纯虚函数,也叫做抽象类。
这个时候子对象必须实现纯虚函数,否则会报错……
这一章内容不多,就没有练习题了。
下一章:运算符重载。