继承与多态

来源:互联网 发布:红马后一计划软件 编辑:程序博客网 时间:2024/06/06 09:19

继承:

保护已有类的特性而构造新类的过程称为继承

在已有类的基础上新增自己的特性而产生新类的过程称为派生

被继承的已有类称为基类(或父类);

派生出的新类称为派生类(或子类);

继承的目的:实现代码重用

派生的目的:当新的问题出现,原有程序无法解决时,需要对原有程序进行改造

三种继承方式:

公有继承,

私有继承,

保护继承。


1:当基类有默认构造函数时,当创建派生类的对象时,派生类的构造函数会自动调用基类的构造函数

2:当激烈没有默认构造函数时,派生类的构造函数必须使用初始化参数列表来调用基类的构造函数

3:在构造子类对象时,先执行父类构造对象,然后执行参数类的构造函数,最后执行子类构造函

例:

#include<iostream>using namespace std;class Father{    protected:int f_data;      public:Father(int x):f_data(x){}Father(){f_data=1;}};class Son:public Father         <span style="color:#ff6666;"> </span><span style="color:#ff0000;"> //以public继承</span>{    private:int s_data;    public:Son(int x):s_data(x){}Son(){s_data=11;}void show(){    cout<<"f_data:"<<f_data<<endl;  <span style="color:#ff0000;">//打印继承父类的id</span>    cout<<"s_data:"<<s_data<<endl; }};int main(){    Son s1;    s1.show();    return 0;}

赋值兼容规则:

派生类对象可以赋值给基类对象  (比如要动物我们可以给猴子)

派生类对象可以初始化基类引用

派生类对象的地址可以赋值给指向基类的指针(放动物的地方我们可以放猴子)


#include<iostream>using namespace std;class A{    public:void show(){    cout<<"A"<<endl;}};class B:public A{    public:void show(){    cout<<"B"<<endl;}};class C:public B{    public:void show(){    cout<<"C"<<endl;}};void fun(A* ptr){    ptr->show();}int main(){    A a1,*p;      <span style="color:#ff0000;">//通过指针指向,指针首先指向其继承部分,所以一直打印:A</span>    B b1;    C c1;    p=&a1;    fun(p);   <span style="color:#ff0000;"> //显示为:A</span>    p=&b1;    fun(p);    <span style="color:#ff0000;">//显示为:A</span>    p=&c1;    fun(p);   <span style="color:#ff0000;"> //显示为:A</span>    return 0;}

多态:

c++多态是通过虚函数实现的,虚函数允许子类重新定义成员函数,而子类重写定义弗雷接口的做法成为覆盖或重写

子类需要公有继承父类

定义父类的指针或引用,然后通过指针或引用去调用相应的虚函数

虚函数:

成员函数之前加上virtual 关键字,就是虚成员函数。

判断是否为虚函数:

1:该函数与基类的虚函数有相同的函数名

2:该函数与基类的虚函数有相同的残苏个数与对应的参数类型

3:该函数与基类虚函数有相同的返回值或者满足赋值兼容规则的指针,引用的返回值

#include<iostream> using namespace std;class A{    public:    virtual void show()          <span style="color:#ff0000;">//虚成员函数</span>{    cout<<"A"<<endl;}};class B:public A{    public:void show()<span style="color:#ff0000;">//虚成员函数</span>{    cout<<"B"<<endl;}};class C:public B//虚成员函数{    public:void show(){    cout<<"C"<<endl;}};void fun(A* ptr){    ptr->show();}int main(){    A a1,*p;      <span style="color:#ff0000;">//通过虚函数,重写父函数</span>    B b1;    C c1;    p=&a1;    fun(p);   <span style="color:#ff0000;"> //显示为:A</span>    p=&b1;    fun(p);    <span style="color:#ff0000;">//显示为:B</span>    p=&c1;    fun(p);   <span style="color:#ff0000;"> //显示为:C</span>    return 0;}

多态与非多态区别:

区别就是地址是早绑定还是晚绑定,如果函数的调用在编译期间就可以确定函数的调用地址,并产生代码,就是静态的也就是早绑定是非多态的。而如果函数的调用地址不能在编译期间确定,需要在运行时才确定,这就是晚绑定也称动态联编,是多态的

重载与重写区别:

重载overload:函数名相同,参数列表不同,在同类内部存在,不以返回值判断

重写overwrrte:也称为覆盖,子类重新定义父类中的同名函数。函数特征相同,单数具体实现不同,基类的函数要有关键字virtual,主要是在继承关系中出现。


组合和继承:

组合是has,继承是is,比如眼睛,猴子适合于组合,而动物,猴子适合用继承。

虚拟继承:

沙发:可以看电视,有重量

床:可以睡觉,有重量

沙发床:继承沙发和床,既可以睡觉,又可以看电视sleeper_sofa:public bed,public sofa  //出错,沙发床不能有两个重量

所以先把重量定义为一类,然后沙发和床都虚拟继承该类。

#include<iostream>using namespace std;class Furniture{    int weight;    public:    Furniture(){cout<<"Furniture()"<<endl;}    ~Furniture(){cout<<"~Furniture()"<<endl;}    void setweight(int x)    {weight=x;    }    void getweight()    {cout<<weight<<endl;    }};class Sofa:<span style="background-color: rgb(255, 204, 0);">virtual</span> public Furniture{    public:Sofa(){cout<<"Sofa()"<<endl;}~Sofa(){cout<<"~Sofa()"<<endl;}void watch_tv(){    cout<<"watch_tv"<<endl;}};class Bed:<span style="background-color: rgb(255, 255, 0);">virtual</span> public Furniture{    public:Bed(){cout<<"Bed()"<<endl;}~Bed(){cout<<"~Bed()"<<endl;}void sleep(){    cout<<"sleeping"<<endl;}};class Sleepersofa:public Bed,public Sofa{    public:Sleepersofa(){cout<<"Sleepersofa()"<<endl;}~Sleepersofa(){cout<<"~Sleepersofa()"<<endl;}void Foldout(){    cout<<"Fold out the sofa"<<endl;}};int main(){    Sleepersofa s1;    s1.setweight(20);    s1.getweight();    cout<<endl;}skywalker@skywalker:~/item$ ./a.out <span style="white-space:pre"><span style="color:#cc0000;"></span></span><span style="color:#cc0000;">//结果如下</span>Furniture()Bed()Sofa()Sleepersofa()20~Sleepersofa()~Sofa()~Bed()~Furniture()

构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:
1:任何虚拟基类的构造函数按照它们被继承的顺序构造
2:任何非虚拟基类的构造函数按照它们被继承的顺序构造;
3:任何成员对象的构造函数按照它们声明的顺序调用;
4:类自己的构造函数。

0 0