C++ Day8 类与对象 下 继承与多态

一、继承

  • 减少重复的代码

1.1基础

  • class 子类(派生类):继承方式 父类(基类);

1.2 继承方式

  • 公共继承:class 子类(派生类):public 父类(基类);父类中公共的属性继承过来还是公共的,保护还是保护
  • 保护继承:class 子类(派生类):protected父类(基类);公共权限变成保护权限保护还是保护
  • 私有继承:class 子类(派生类):private 父类(基类);公共和保护都变成私有权限

注意:

  • 三种继承方式都无法访问父类的私有属性

1.3 对象模型

  • 父类的所有非静态成员属性都会被子类继承下去
  • 父类的私有成员属性访问不到被编译器隐藏,但是继承了
#include<iostream>
using namespace std;
class person
{
    public:
        int a;
    protected:
        int b;
    private:
        int c;
};
class student:public person
{
    public:
        int d;
};
int main()
{
    cout<<sizeof(student);//16
    system("pause");
}

1.4 继承中构造和析构的顺序

  • 现有父类构造函数再有子类构造函数和析构函数,最后父类析构函数

1.5 继承中同名成员

当子类和父类有相同名称的成员:

  • 访问子类同名成员直接访问。
  • 访问父类同名成员,加上作用域。
  • 父类所有同名成员会被隐藏
#include<iostream>
using namespace std;

class person
{
    public:
        int a=11;
    void fre()
    {
        cout<<a<<endl;
    }
    
};
class student:public person
{
    public:
        int a=10;
    void fre()
    {
        cout<<a<<endl;
    }
};
int main()
{
    student s;
    cout<<s.a<<endl;
    cout<<s.person::a<<endl;//加上作用域
    s.fre();
    s.person::fre();//加上作用域
    system("pause");
}

1.6 同名静态成员

  • 和上面处理方式一致
  • 可以通过类名的方式访问:student::person::fre();

1.7 多继承

  • 语法:class 子类:继承方式 父类1,继承方式 父类2;
  • 不建议使用

1.8 菱形继承(钻石继承)

  • 定义:两个子类继承同一个父类,又有子类同时继承上面两个类
  • 问题:数据有两份造成,比如年龄有两个。
  • 利用虚继承解决菱形继承问题。class student:virtual public person{};
  • 虚继承底层:没有继承数据而是继承了虚基类指针(vbptr),该指正指向一个虚基类表(vbtable),该表中纪录偏移量,通过偏移量找到数据。

二、多态

2.1 基础

分类:

  • 静态多态:包括函数重载和运算符重载,复用函数名
  • 动态多态:子类和虚函数实现运行时多态。

区别:

  • 静态多态:函数地址早绑定:编译阶段确定地址
  • 动态多态:函数地址晚绑定:运行阶段确定地址

虚函数实现地址的晚绑定

#include<iostream>
using namespace std;

class person
{
    public:
    virtual void say()//加上virtual后变成虚函数,该函数的地址在运行阶段绑定
    {
        cout<<"人说话"<<endl;
    }
    
};
class student:public person
{
    public:
    void say()
    {
        cout<<"学生说话"<<endl;
    }
};
void test(person &person)//地址早绑定
{
    person.say();
}
int main()
{
    student s;
    test(s);//想让学生说话,结果是人,因为早绑定,地址在编译阶段已经确定
    system("pause");
}

动态多态的条件:
- 1.有继承关系
- 2.子类重写父类的虚函数,重写:函数的返回值,函数名,参数列表完全相同

  • 动态多态底层原理:虚函数生成虚函数指针(vfptr)指向一个虚函数表,虚函数表中存储函数的地址,当子类重写父类虚函数时,子类将子类的虚函数表中地址指向自己,当父类引用指向子类对象时,会去找子类的虚函数表中地址。

2.2 纯虚函数和抽象类

  • 通常父类虚函数的实现无意义,可将虚函数改为纯虚函数
  • 语法:virtual 返回值类型 函数名(参数列表)=0;
  • 抽象类:有纯虚函数的类
  • 抽象类无法实例化对象,子类必须重写抽象类中的纯虚函数

2.3 多态示例

做饮品:

#include<iostream>
using namespace std;
class Abstractdrink//抽象类
{
public:
    virtual void water()=0;
    virtual void wash()=0;
    virtual void pull()=0;
    virtual void addmaterial()=0;
    virtual void make()
    {
        water();
        wash();
        pull();
        addmaterial();
    }
};

class coffee: public Abstractdrink
{

    void water()
    {
        cout<<"1.煮水"<<endl;
    }
    void wash()
    {
        cout<<"2.冲泡咖啡"<<endl;
    }
    void pull()
    {
        cout<<"3.倒入杯中"<<endl;
    }
    void addmaterial()
    {
        cout<<"4.加糖"<<endl;
    }
        public:

};

class tea: public Abstractdrink
{
    
    void water()
    {
        cout<<"1.煮水"<<endl;
    }
    void wash()
    {
        cout<<"2.冲泡茶叶"<<endl;
    }
    void pull()
    {
        cout<<"3.倒入杯中"<<endl;
    }
    void addmaterial()
    {
        cout<<"4.柠檬"<<endl;
    }
    public:
};

void makedrink(Abstractdrink &drink)
{
    drink.make();//一个接口实现多个
}

int main()
{
    tea t;
    coffee c;
    makedrink(t);//一个接口实现多个
    cout<<endl;
    makedrink(c);//一个接口实现多个
    system("pause");
}

2.4 虚析构和纯虚析构

  • 使用多态是父类指针无法释放子类的析构代码,导致内存泄露。
  • 将父类中的析构函数改为虚析构或纯虚析构。
  • 纯虚析构既要声明又要实现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值