虚函数与重载函数的关系
我们现在来比较一下规则比较多的虚函数和规则比较少的重载函数之间的差别:
-
普通函数重载时,其函数的参数个数或者参数类型必须有所不同,函数的返回类型也可以不同。(这个不同是比较严格的不同,是涉及本质的)
-
重载函数: 要求函数名、返回类型、参数个数、参数的类型和顺序与基类中的虚函数完全相同。如果发生不同则分以下两种情况:
1.返回值类型不同,其他相同-------->系统报错
2.仅函数名相同,其他都不同--------->系统直接判其为重载,失去虚函数特征。
总结:
- 可以看出重载函数是“因为相同,所以一定要找出点不同来方便静态联编去辨认。”而重载函数时“我相信动态联编有这个辨识能力,所以我选择都一样,让动态联编自己去选择。”
- 虚函数的条件比函数重载要严格,基本上除了函数体内具体操作,能一致的都保持一致了,一但有一点不同,系统就判为重载了。
纯虚函数
纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但要求在它的派生类中必须定义自己的版本,或重新说明为纯虚函数。
纯虚函数的定义为:
virtual 函数类型 函数名(参数表)=0**;**//最后一个分号不要忘!
其实其主要区别就是书写形式上在后面加了个“=0”,表明在基类中不用定义该函数,它的实现留给派生类去做。(纯虚函数只是给了个名字而已,接下来怎么实现都要靠后面派生类中的函数来构造,最后的“=0”只是个符号,不代表返回值为0).
假如一个类中声明了纯虚函数,而在其派生类中没有对该函数的定义,则该虚函数在派生类中仍然为纯虚函数。
抽象类
如果一个类中至少有一个纯虚函数,那么就称该类为抽象类。
(抽象类和纯虚函数是一个捆绑的概念,只要有了纯虚函数就会有抽象类)
抽象类只能作为其他类的基类来使用,不能建立抽象类的对象,其纯虚函数的实现由派生类给出。
派生类中必须重载类中纯虚函数,系统会认为该类把纯虚函数也继承了,所以类内有纯虚函数,会把该派生类视为抽象类,因此也不能定义自己的对象。
抽象类的几点注意
标准化例子:
#include<iostream.h>
class Circle{ //定义了纯虚函数,Circle就变成了抽象类
public:
void setr(int x){r=x;} //纯虚函数虽然不能定义自己的对象但也可以//
//定义成员以及成员函数,通过派生类的形式将 //其调用出来。
virtual void show()=0 //“=”0不表示返回值为0,是一个纯虚函数符号
virtual~Circle() = 0; //析构函数也可以是纯虚函数
protected:
int r;
};
class Area:public Circle {
public:
void show(){cout<<Area is <<3.14*r*r<<endl;}
~Area(){cout<<"The circle is deleted"<<endl;}//至少提供一种纯虚函数的实现方案
};
class Perimeter:public Circle{
public:
void show(){cout<<"Perimeter is"<<2*3.14*r<<endl;}
~Perimeter(){cout<<"The circle is deleted"<<endl;}//至少提供一种纯虚函数的实现方案
};
void main()
{
Circle *ptr;
Circle ptr; //此处是错误用法,不能用抽象类定义对象。
Area ob1;
Perimeter ob2;
ob1.setr(10);
ob2.setr(10);
ptr = &ob1;
ptr->show();
ptr = &ob2();
ptr->show();
}
- 再次强调,不能建立抽象类的对象,但是可以建立抽象类的指针和引用,但这个指针是指向其派生类的,是为了实现其多态性的。
- 不允许从具体类派生出抽象类。(只允许从虚的派生出具体的,不能从具体的派生出虚的。)
- 抽象类既然不能定义对象,当然也不能作为参数类型、函数返回值或是显式转换类型。
- 析构函数也可以实现纯虚函数,这时,应该至少提供一个实现。