目录
笔记部分:
1.若要访问派生类中相同名字的函数,必须将基类中的同名函数定义为虚函数,这样,将不同的派生类对象的地址赋给基类的指针变量后,就可以动态地根据这种赋值语句调用不同类中的函数。
2.虚函数的定义和使用:
可以在程序运行时通过调用相同的函数名而实现不同功能的函数称为虚函数。定义格式为:
virtual <type> FuncName(<ArgList>);
一旦把基类的成员函数定义为虚函数,由基类所派生出来的所有派生类中,该函数均保持虚函数的特性。
在派生类中重新定义基类中的虚函数时,可以不用关键字virtual来修饰这个成员函数 。
3.虚函数是用关键字virtual修饰的某基类中的protected或public成员函数。它可以在派生类中重新定义,以形成不同版本。只有在程序的执行过程中,依据指针具体指向哪个类对象,或依据引用哪个类对象,才能确定激活哪一个版本,实现动态聚束。
关于虚函数,说明以下几点:
1、当在基类中把成员函数定义为虚函数后,在其派生类中定义的虚函数必须与基类中的虚函数同名,参数的类型、顺序、参数的个数必须一一对应,函数的返回的类型也相同。若函数名相同,但参数的个数不同或者参数的类型不同时,则属于函数的重载,而不是虚函数。若函数名不同,显然这是不同的成员函数。
2、实现这种动态的多态性时,必须使用基类类型的指针变量,并使该指针指向不同的派生类对象,并通过调用指针所指向的虚函数才能实现动态的多态性。
3、虚函数必须是类的一个成员函数,不能是友元函数,也不能是静态的成员函数。
4、在派生类中没有重新定义虚函数时,与一般的成员函数一样,当调用这种派生类对象的虚函数时,则调用其基类中的虚函数。
5、可把析构函数定义为虚函数,但是,不能将构造函数定义为虚函数。
6、虚函数与一般的成员函数相比较,调用时的执行速度要慢一些。为了实现多态性,在每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现的。因此,除了要编写一些通用的程序,并一定要使用虚函数才能完成其功能要求外,通常不必使用虚函数。
7、一个函数如果被定义成虚函数,则不管经历多少次派生,仍将保持其虚特性,以实现“一个接口,多个形态”。
虚函数的访问
用基指针访问与用对象名访问
用基指针访问虚函数时,指向其实际派生类对象重新定义的函数。实现动态聚束。
通过一个对象名访问时,只能静态聚束。即由编译器在编译的时候决定调用哪个函数。
纯虚函数
在基类中不对虚函数给出有意义的实现,它只是在派生类中有具体的意义。这时基类中的虚函数只是一个入口,具体的目的地由不同的派生类中的对象决定。这个虚函数称为纯虚函数。
需要注意的问题:
1、在定义纯虚函数时,不能定义虚函数的实现部分。
2、把函数名赋于0,本质上是将指向函数体的指针值赋为初值0。与定义空函数不一样,空函数的函数体为空,即调用该函数时,不执行任何动作。在没有重新定义这种纯虚函数之前,是不能调用这种函数的。
3、把至少包含一个纯虚函数的类,称为抽象类。这种类只能作为派生类的基类,不能用来说明这种类的对象。
其理由是明显的:因为虚函数没有实现部分,所以不能产生对象。但可以定义指向抽象类的指针,即指向这种基类的指针。当用这种基类指针指向其派生类的对象时,必须在派生类中重载纯虚函数,否则会产生程序的运行错误。
4、在以抽象类作为基类的派生类中必须有纯虚函数的实现部分,即必须有重载纯虚函数的函数体。否则,这样的派生类也是不能产生对象的。
综上所述,可把纯虚函数归结为:抽象类的唯一用途是为派生类提供基类,纯虚函数的作用是作为派生类中的成员函数的基础,并实现动态多态性。
虚基类
多基派生中的多条路径具有公共基类时,在这条路径的汇合处就会因对公共基类产生多个拷贝而产生同名函数调用的二义性。
解决这个问题的办法就是把公共基类定义为虚基类,使由它派生的多条路径的汇聚处只产生一个拷贝。
由虚基类派生出的对象初始化时,直接调用虚基类的构造函数。因此,若将一个类定义为虚基类,则一定有正确的构造函数可供所有派生类调用。
用虚基类进行多重派生时,若虚基类没有缺省的构造函数,则在每一个派生类的构造函数中都必须有对虚基类构造函数的调用 (且首先调用)。
代码框架:
代码部分:
#include <iostream>
using namespace std;
#define PI 3.14
class shape//抽象类:包含纯虚函数的类叫做抽象类
//抽象类的特点:不能被实例化,不能创建对象
{
public:
virtual double area()const { return 0.0; }//const 只读函数
virtual double volume()const { return 0.0; }
virtual void shapename()const = 0;//纯虚函数
};
//继承了抽象类之后,如果没有对父类纯虚函数加以实现,
//则子类也不能被实例化
class point :public shape
{
protected:
double x;
double y;
public:
point(double x = 0, double y = 0);
virtual void shapename()const//纯虚函数
{
cout << "point" << endl;
}
friend ostream& operator <<(ostream&, const point&);//输出流重载函数
};
point::point(double x, double y)
{
this->x = x;
this->y = y;
}
ostream& operator <<(ostream& output, const point& p)
{
output << "[" << p.x << "," << p.y << "]" << endl;
return output;
}
class circle :public point
{
protected:
double radius;
public:
virtual void shapename()const//纯虚函数
{
cout << "circle" << endl;
}
circle() { cout << "circle类的无参构造函数正在执行……" << endl; };
circle(double x, double y, double r) :point(x, y), radius(r)
{this->x = x; this->y = y; this->radius = r;}
virtual double area()const;
friend ostream& operator <<(ostream&, const circle&);//输出流重载函数
};
double circle::area()const { return PI * radius * radius; }
ostream& operator <<(ostream& output, const circle &c)
{
output << "[" << c.x << "," << c.y << "]" <<c.area()<< endl;
return output;
}
class cylinder :public circle
{
public:
cylinder(double, double, double, double);
virtual double area()const;
virtual double volume()const;
virtual void shapename()const { cout << "cylinder" << endl; }
friend ostream& operator <<(ostream&, const cylinder&);//输出流重载函数
protected :
double height;
};
cylinder::cylinder(double x, double y, double r, double h) :circle(x, y, r), height(h)
{
this->x = x; this->y = y; this->radius = r; this->height = h;
}
double cylinder::area() const
{
return circle::area() * 2 + 2 * PI * radius * height;
}
double cylinder::volume() const
{
return circle::area() * height;
}
ostream& operator <<(ostream& output, const cylinder& c)
{
output << "[" << c.x << "," << c.y << "]"
<< c.area() <<" "<<c.volume()<< endl;
return output;
}
void USB(shape* pt)
{
pt->shapename();//接口调用
}
int main()
{
point p(1.2, 2.3);
circle c(3.3,4.4,5);
cylinder cy(1.1, 2.2, 3.3, 4.4);
USB(&p);
USB(&c);
USB(&cy);
cout << p << endl;
cout << c << endl;
cout << cy << endl;
return 0;
}
//shape
//point
//circle
//cylinder