多态性
-
多重继承
-
虚基类
-
抽象类
-
纯虚函数
为什么要用多继承
#include "iostream"
using namespace std;
class father
{
public:
void smart(){cout<<"父亲很聪明\n";}
//父类的smart()函数
virtual void beautiful(){}
//该虚函数只是给son类做个接口,没有什么实际功能
virtual ~father(){cout<<"析构father"<<endl;}
//父类的虚析构函数
};
class son:public father
{
public:
~son(){cout<<"析构son";}
//子类的析构函数,它也是个虚析构函数
virtual void beautiful(){cout<<"儿子也很帅\n";}
//子类的beautiful函数,即使前面不加virtual,它也是个虚析构函数
};
int main()
{
father*pf;
int choice=0;
while(choice<99) //控制输入为数字,并且在99之内
{
choice=0;
bool Quit=false;
cout<<"(0)退出(1)父亲(2)儿子:";
cin>>choice;
switch(choice)
{
case 0:Quit=true;
break;
case 1: pf=new father;
pf->beautiful();
delete pf;
/*函数调用结束后,删除指针pf,当删除该指针时会自动调用析构函数,一个类只有一个析构函数,由于这里我们将析构函数设置为virtual,因此程序将动态地调用两个类中合适虚析构函数*/
break;
case 2:pf=new son;
pf->beautiful();
delete pf;
break;
default:cout<<"请输入从0到2之间的数字。";
}
if (Quit)
break;
}
cout<<"程序结束"<<endl;
}
父类有一个无用的虚函数beautiful(),只为给子类做接口。如果有很多子类各有特征岂不是加很多无用函数。
-
dynamic_cast(还记的static_cast?)
dynamic_cast是将一个基类对象指针(或引用)转换到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理。dynamic_cast运算符涉及到编译器的属性设置,而且牵扯到的面向对象的多态性跟程序运行时的状态也有关系,所以不能完全的使用传统的替换方式来代替。但是也因此它最常用,是最不可缺少的一个运算符。
格式: type-id a = dynamic_cast<type-id>( expression )
说明:该运算符把expression转换成type-id类型的对象。Type-id 必须是类的指针、类的引用或者void*;如果 type-id 是类指针类型,那么expression也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用。dynamic_cast运算符可以再执行期决定真正的类型。如果downcast是安全的(也就是说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(即基类指针或者引用没有指向一个派生类对象)。
用法:
1.dynamic_cast在类层次间进行向上转换时,效果和static_cast一样。
2.dynamic_cast在类层次间进行向下转换时,具有类型检查功能,更安全。
注意:dynamic_cast 转换中父类一定要有虚函数
#include<iostream>
using namespace std;
class father
{
public:
virtual void smart(){cout<<"父亲很聪明\n";}
};
class son:public father
{
public:
virtual void beautiful(){cout<<"儿子也很帅\n";}
//子类的beautiful函数
};
int main()
{
father *Mike[5];
father*pf;
int choice,i;
for(i=0;i<5;i++)
{
cout<<"(1)father(2)son;";
cin>>choice;
if(choice==2)
pf=new son;
else
pf=new father;
Mike[i]=pf;
son *ps=dynamic_cast<son*>(Mike[i]);//
//将指向父类的Mike[i]转成指向子类的指针,然后赋给子类的指针ps
if(ps)//转换成功
ps->beautiful();
else //转换不成功
cout<<"父亲的指针\n";
delete Mike[i];
}
cout<<"\n";
return 0;
}
//这不是多态,转换后ps只能范问派生类的成员,这违背了多态
多重继承
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class father
{
public:
father(){cout<<"创建父亲..."<<endl;}
virtual ~father(){cout<<"析构父亲..."<<endl;}
virtual void smart()const{cout<<"父亲很聪明!"<<endl;}
};
class mother
{
public:
mother(){cout<<"创建母亲"<<endl;}
virtual ~mother(){cout<<"析构母亲..."<<endl;}
virtual void beautiful()const{cout<<"母亲很漂亮..."<<endl;}
};
class son:public father,public mother
{
public:
son(){cout<<"创建儿子..."<<endl;}
virtual void beautiful()const{cout<<"儿子很帅..."<<endl;}
virtual void smart()const{cout<<"儿子很聪明!"<<endl;}
~son(){cout<<"析构儿子..."<<endl;}
};
int main()
{
father *Mike[2];
mother *Mary[2];
father *pf;
mother *pm;
int choice,i;
for(i=0;i<2;i++)
{
cout<<"\n (1)父亲(2)儿子:";
cin>>choice;
if(choice==2)
pf=new son;
else
pf=new father;
Mike[i]=pf;
cout<<"\n Mike["<<i<<"]:";
Mike[i]->smart();
delete Mike[i];
}
for(i=0;i<2;i++)
{
cout<<"\n (1)母亲()儿子:";
cin>>choice;
if(choice==1)
pm=new mother;
else
pm=new son;
Mary[i]=pm;
cout<<"\n Mary["<<i<<"]:";
Mary[i]->beautiful();
delete Mary[i];
}
cout<<"\n";
return 0;
}
多继承中初始化构造函数参数
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class father
{
public:
father(int height);
virtual ~father(){cout<<"析构父亲..."<<endl;}
virtual void smart()const{cout<<"父亲很聪明!"<<endl;}
virtual int getHeight()const{return _height;}
private:
int _height;
};
father::father(int height):_height(height)
{
cout<<"创建父亲\n";
}
class mother
{
public:
mother(bool sex);
virtual ~mother(){cout<<"析构母亲..."<<endl;}
virtual void beautiful()const{cout<<"母亲很漂亮..."<<endl;}
virtual bool getSex()const{return _sex};
private:
bool _sex;
};
mother::mother(bool sex):_sex(sex)
{
cout<<"创建母亲\n";
}
class son:public father,public mother
{
public:
son(int,bool,long);
~son(){cout<<"析构儿子..."<<endl;}
virtual long getNum()const
{
return num;
}
private:
long _num;
};
son::son(int height,bool sex,long number):father(_height),mother(_sex),num(_number)//看这
{
cout<<"创建儿子\n";
}
int main()
{
son *ps = new son(5,true,3);
ps->beautiful();
ps->smart();
ps->getHeight();
ps->getSex();
ps->getNum();
}
多个子基类共享一个父类
#include <iostream>
using namespace std;
class human
{
public:
human(int);
virtual ~human(){cout<<"析构人类"<<endl;}
virtual int walk(){return itswalk;}
virtual void setwalk(int walk){itswalk=walk;}
private:
int itswalk;
};
human::human(int walk):itswalk(walk)
{
cout<<"创建人类"<<endl;
}
class father:public human
{
public:
father(int walk,int wit);
virtual ~father(){cout<<"析构父亲\n";}
virtual int getwit()const{return itswit;}
virtual int walk(){return itswalk;}
virtual void setwalk(int walk){itswalk=walk;}
protected:
int itswit;
int itswalk;
};
father::father(int walk,int wit):human(walk),itswalk(walk), itswit(wit)
{
cout<<"创建父亲"<<endl;
}
class mother:public human
{
public:
mother(bool sex,int walk);
virtual ~mother(){cout<<"析构母亲\n";}
virtual bool sex()const{return itsex;}
virtual void setsex(bool sex){itsex=sex;}
protected:
bool itsex;
};
mother::mother(bool sex,int walk):human(walk),itsex(sex)
{
cout<<"构造母亲\n";
}
class son:public father,public mother
{
public:
void beautiful()const{cout<<"儿子也很帅\n";}
son(bool sex,int walk,int wit);
virtual ~son(){cout<<"析构儿子\n";}
virtual int getwit()const{return itswit;}
virtual bool sex()const{return itsex;}
virtual void setsex(bool sex){itsex=sex;}
virtual int walk(){return itswalk;}
private:
int itswit;
int itswalk;
bool itsex;
};
son::son(bool sex,int walk,int wit):father(walk, wit), mother(sex,walk), itsex(sex), itswit(wit), itswalk(walk)
{
cout<<"创建儿子\n";
}
int main()
{
son *ps=new son(true,50,80);
int wit=ps->getwit();
cout<<"儿子的智商为:"<<wit<<endl;
cout<<"儿子的行走速度为:每小时"<<ps->walk()<<"英里。"<<endl;
if(ps->sex())cout<<"儿子是男性。\n";
else cout<<"无法确定性别\n";
ps->father::setwalk(40);
cout<<"父亲的行走速度为:每小时"<<ps->father::walk()<<"英里。"<<endl;
ps->mother::setsex(false);
if(ps->mother::sex())
cout<<"无法确定性别\n";
else
cout<<"母亲是女性。\n";
delete ps;
return 0;
}
以上程序子类实际上继承了两次母亲和父亲的共有基类---人类。分析程序输出。
虚基类
#include <iostream>
using namespace std;
class human
{
public:
int func(){return 1;}
};
class father:virtual public human
{
};
class mother:virtual public human
{
};
class son:public father,public mother
{
};
int main()
{
son a;
cout<<a.func()<<endl;
return 0;
}
去掉virtual试试。
这就是虚继承的作用,使得基类只产生一个实例。
//修改前面的例子
//在分析输出结果
#include <iostream>
using namespace std;
class human
{
public:
human(int);
virtual ~human(){cout<<"析构人类"<<endl;}
virtual int walk(){return itswalk;}
private:
int itswalk;
};
human::human(int walk):itswalk(walk)
{
cout<<"创建人类"<<endl;
}
class father:virtual public human//虚继承
{
public:
father(int walk,int wit);
virtual ~father(){cout<<"析构父亲\n";}
virtual int wit()const{return itswit;}
protected:
int itswit;
};
father::father(int walk,int wit):human(walk),itswit(wit)
{
cout<<"创建父亲"<<endl;
}
class mother:virtual public human//虚继承
{
public:
mother(bool sex,int walk);
virtual ~mother(){cout<<"析构母亲\n";}
virtual bool sex()const{return itsex;}
protected:
bool itsex;
};
mother::mother(bool sex,int walk):human(walk),itsex(sex)
{
cout<<"构造母亲\n";
}
class son:public father,public mother
{
public:
void beautiful()const{cout<<"儿子也很帅\n";}
son(bool sex,int walk,int wit);
virtual ~son(){cout<<"析构儿子\n";}
};
son::son(bool sex,int walk,int wit):human(walk),father(walk, wit),
mother(sex,walk)
{
cout<<"创建儿子\n";
}
int main()
{
son *ps=new son(true,20,80);
ps->beautiful();
cout<<"一般人类的行走速度为:每小时"<<ps->walk()<<"英里。"<<endl;
if(ps->sex())cout<<"母亲是女性。\n";
else cout<<"无法确定性别\n";
cout<<"父亲的智商为:"<<ps->wit()<<endl;
delete ps;
return 0;
}
抽象类和纯虚函数
很多时候基类的虚函数都不会实例化.而只是作为一个往下传递的接口。
#include <iostream>
using namespace std;
//这个shape类其实没什么具体功能,只是提供了一些接口。是一个抽象的概念,就像人类,他不是某个具体的人,没有实际功能
class shape
{
public:
shape(){}
virtual ~shape(){}
virtual float length(){return 0;}
virtual float area(){return 0;}
virtual void show(){}
private:
};
class A :public shape
{
public:
A(float i,float j):w(i),l(j){}
virtual ~A(){}
virtual float width(){return w;}
virtual float length(){return l;}
virtual float area(){return w*l;}
virtual void show(){cout<<"长方形的面积为:"<<area()<<endl;}
protected:
float w;
float l;
};
class B :public A
{
public:
B(float i,float j):A(i,j),w(i),l(j){}
virtual ~B(){}
virtual float width(){return w;}
virtual float length(){return l;}
virtual float area(){return w*l/2;}
virtual void show(){cout<<"三角形的面积为:"<<area()<<endl;}
protected:
float w;
float l;
};
class C :public shape
{
public:
C(float j):l(j){}
virtual ~C(){}
virtual float length(){return l;}
virtual float area(){return l*l*3.14;}
virtual void show(){cout<<"圆的面积为:"<<area()<<endl;}
protected:
float l;
};
int main()
{
shape *p;
p=new A(23,34);
p->show();
delete p;
p=new B(11,12);
p->show();
delete p;
p=new C(45);
p->show();
p=new shape;//对比后面纯虚函数,此处可以实例化,此类相当于模拟抽象类
p->show();
delete p;
return 0;
}
纯虚函数
C++支持用纯虚函数来创建抽象类.一个虚函数通过初始化为0会变成纯虚函数.
一个类可以说明多个纯虚函数.包含有纯虚函数的类也被叫做抽象类,抽象类不能被实例化
virtual float length()=0;//注意这里的等于0
由于任何一个从抽象类派生的新类都会继承纯虚函数的特征一无任何功能, 因此它要实例化对象,必须覆盖掉每一个纯虚函数。
#include <iostream>
using namespace std;
class shape
{
public:
virtual double area()=0;//纯虚函数
};
class A:public shape
{
protected:
double h,w;
public:
A(double H,double W){h=H,w=H;}
double area(){return h*w/2;}
};
class B:public A
{
public:
B(double H,double W):A(H,W){}
double area(){return h*w;}
};
class C:public shape
{
protected:
double radius;
public:
C(double r){radius=r;}
double area(){return radius*radius*3.14;}
};
int main()
{
shape*s;
int choice=0;
while(choice<9)
{
choice=0;
bool quit=false;
cout<<"(0)退出(1)三角形( 2)长方形(3)圆"<<endl;
cout<<"请选择:";
cin>>choice;
switch(choice)
{
case 0:quit=true;
break;
case 1:s=new A(5.0,6.0);
cout<<"三角形的面积为:"<<s->area()<<endl;
break;
case 2:s=new B(70.0,80.0);
cout<<"长方形的面积为:"<<s->area()<<endl;
break;
case 3:s=new C(9.0);
cout<<"圆的面积为:"<<s->area()<<endl;
break;
default:cout<<"请输入到之间的数字。";
break;
}
if(choice<4&&choice>0)
delete s;
if(quit)
break;
}
}
-
最后一个例子:
#include <iostream>
using namespace std;
class animal
{
public:
animal(int);
virtual ~animal(){cout<<"析构动物..\n";}
virtual int getage() {return itsage;}
virtual void sleep()=0; //声明6个纯虚函数
virtual void eat()=0;
virtual void propagate()=0;
virtual void move()=0;
virtual void body()=0;
virtual void show()=0;
private:
int itsage;
};
animal::animal(int age):itsage(age)
{
cout<<"创建动物...\n";
}
class Mammalia:public animal //派生了另一个抽象类哺乳动物类
{
public:
Mammalia(int age):animal(age){cout<<"创建哺乳类...\n";}
//子类在构造自己的同时也要构造基类部分
virtual ~Mammalia(){cout<<"析构哺乳类...\n";}
virtual void propagate(){cout<<"哺乳类是胎生动物,通过胚胎来繁殖后代。\n";}
//该类仅仅覆盖了基类的繁殖方法propagate() 注意是覆盖
};
class bird:public animal //鸟类将动物类的6个纯虚函数全部覆盖,因此该类不是抽象类
{
public:
//子类在构造自己的同时也要构造基类部分
bird(int age):animal(age){cout<<"创建鸟类...\n";}
virtual ~bird(){cout<<"析构鸟类...\n";}
virtual void sleep(){cout<<"鸟类喜欢站着睡觉。\n";}
virtual void eat(){cout<<"极个别鸟类吃肉,其他都是吃素。\n";}
virtual void propagate(){cout<<"鸟类是卵生动物,通过排卵来繁殖后代.";}
virtual void move(){cout<<"鸟类可以飞...\n";}
virtual void body(){cout<<"鸟类体表被覆羽毛,前肢变为翼!";}
virtual void show(){cout<<"鸟类的一般寿命为:"<<getage()<<endl;}
};
class human:public Mammalia //人类从抽象类--哺乳动物类派生而来
{
public:
human(int age):Mammalia(age){cout<<"创建人类...\n";} //子类在构造自己的同时也要构造基类部分
virtual ~human(){cout<<"析构人类...\n";}
//由于基类是个抽象类,因此如果要使该类起作用,那么就要将5个纯虚函数全部覆盖,这里覆盖了6个
virtual void body(){cout<<"人类体表无毛...\n";}
virtual void sleep(){cout<<"人类睡觉也很讲究,要在床上睡觉。\n";}
virtual void eat(){cout<<"人类吃饭很讲究,不吃生食。\n";}
virtual void move(){cout<<"人类靠两条腿走路。\n";}
virtual void propagate(){cout<<"人类通过胚胎繁殖后代.\n";}
virtual void show(){cout<<"人类的一般寿命为:"<<getage()<<endl;}
};
class pig:public Mammalia //猪类也是从抽象类--哺乳动物类派生而来
{
public:
//子类在构造自己的同时也要构造基类部分
pig(int age):Mammalia(age){cout<<"创建猪类...\n";}
virtual ~pig(){cout<<"析构猪类...\n";}
//这里也将抽象类Mammalia的6个方法全部覆盖
virtual void body(){cout<<"猪体表被毛...\n";}
virtual void sleep(){cout<<"猪喜欢在烂泥里睡觉。\n";}
virtual void eat(){cout<<"猪虽然嘴谗,但是吃饭却不讲究。\n";}
virtual void move(){cout<<"猪用四肢走路。\n";}
virtual void propagate(){cout<<"猪类也通过胚胎来繁殖后代.\n";}
virtual void show(){cout<<"猪类因为要被人宰了吃,所以一般寿命为:"<<getage()<<"年。"<<endl;}
};
int main()
{
animal*ph=0; //声明一个指向动物类的指针ph
int choice=0;
bool quit=false;
while(choice<4)
{
choice=0;
cout<<"(1)猪类(2)人类(3)鸟类(0)退出:";
cin>>choice;
switch(choice)
{
case 1:ph=new pig(1); //选择1,创建猪类对象,并初始化猪类的私有变量itsage的值
break;
case 2:ph=new human(80);//选择2,创建人类对象,并初始化人类的私有变量itsage的值
break;
case 3:ph=new bird(50); //选择3,创建鸟类对象,并初始化鸟类的私有变量itsage的值
break; //由于哺乳动物是个抽象类,不能实例化对象,因此没有设置该类的选项
default:quit=true;
break;
}
if(quit)
break;
ph->show(); //用ph指针访问虚函数show,要注意,这里的show()不再是纯虚函数
ph->eat(); //用ph指针访问虚函数eat
ph->propagate(); //用ph指针访问虚函数propagate
ph->move(); //用ph指针访问虚函数move
ph->sleep(); //用ph指针访问虚函数sleep
ph->body(); //用ph指针访问虚函数body
cout<<"\n";
}
return 0;
}