C++基础篇:07 继承与多态

这篇具有很好参考价值的文章主要介绍了C++基础篇:07 继承与多态。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

继承

1 什么是继承

        当遇到问题,先看一下现有的类是否能够解决一部分问题,如果有则继承,并在此基础上进行扩展来解决所有问题,以此缩短解决问题的时间(代码复用)

        当遇到一个大而复杂的问题时,可以把复杂问题拆分成若干个小问题,为每个小问题的解决设计一个类,最后通过继承的方式把这些类汇总到一个类中,从而达到解决大问题的目的,以此降低问题的规模,也可以让多个程序员一起解决该问题

        子类继承父类    派生类继承基类

2 如何继承

2.1 继承表

    class Son : 继承表[继承方式 父类名1,继承方式 父类名2...]
    {
        成员变量;
    public:
        成员函数;
    }

2.2 继承方式

        public        protected        private  

3 C++的继承特点

① C++中的继承可以有多个父类

② 子类会继承父类的所有内容(能否使用另说)

③ 子类对象可以向它的父类类型自动转换(父类类型的指针或引用可以指向子类对象)(允许缩小),但是父类对象不可以向它的子类类型自动转换(子类类型的指针或引用不可以指向父类对象)(不允许扩大)       

Base* b = new Son;  true
Base& b = son;      true
Son* s = new Base;  false
Son& s = base;      false

④ 子类必须以public方式继承父类,才可以让子类对象向它的父类类型自动转换

⑤ 子类会隐藏父类的同名成员,在子类中直接访问同名成员时访问到的是子类的成员

     但可以通过 父类名::同名成员 的方式访问父类的同名成员

⑥ 子类与父类的同名成员函数不能构成重载,因为不在同一个作用域下,子类会隐藏父类的同名函数,只能通过 父类名::同名成员函数() 的方式访问

⑦ 在执行子类的构造函数时,都会先按照继承表顺序执行父类的构造函数,默认执行父类的无参构造,也可以在子类的构造函数的初始化列表中显示调用父类的有参构造,然后再执行类类型成员的构造函数,最后执行子类的构造函数

Son(int num){}              //  Base的无参构造
Son(int num):Base(num){}    //  Base的有参构造

⑧ 在执行子类的析构函数后,再执行类类型成员的析构函数,最后执行父类的析构函数,会按照继承表的逆序执行

⑨ 当子类执行拷贝构造时,默认会调用父类的无参构造,这是不合理的,理应调用父类的拷贝构造进行,因此需要在子类的拷贝构造函数的初始化列表中显式地调用父类的拷贝构造

Son(const Son& that):Base(that) //调用Base拷贝构造

⑩ 当子类执行赋值操作时,默认不会执行父类的赋值函数,如果需要调用父类的赋值函数,可以在子类赋值函数中以 父类名::operator=(that) 方式调用

Son& operator=(const Son& that)
{
    Base::operator=(that);  //  调用父类的赋值操作
}

4 继承方式与访问控制属性

4.1 访问控制属性:限制类成员的访问范围

        public:   可以在类内外任意位置访问

        private:  只能在类内访问

        protected:只能在类内和子类中访问

4.2 继承方式的影响:

① 父类的成员是否能在子类中访问,是由父类设计时成员的访问控制属性决定的,不受子类继承方式的影响

② 如果子类被别的孙子类继承,子类的继承方式会影响父类的成员在孙子类中的访问情况,详情见表格

③ 只有以public继承父类后,父类的指针或引用才能指向子类对象(是多态的基础)

5 多重继承与菱形继承

5.1 多重继承

        当一个子类继承多个父类时,就称为多重继承

        子类中会按照继承表中的顺序排列父类成员,并会标记记录父类成员与首地址的偏移值,当用父类指针指向子类对象时,编译器会自动让父类指针加上对应的偏移值,指向子类中该父类成员的首地址

        当多个不同的父类指针指向同一个子类首地址时,它们的地址值会不同

5.2 菱形继承

        假如有一个类A,类B、类C都各自继承了类A,类D又同时继承类B和类C,此时就构成菱形继承

问题:

        类B、类C中都有类A的内容,类D继承B、C后就有两份类A的内容,还不会报错

        但当类D的对象访问类A的内容时,此时会冲突,因为这样的内容有两份,编译器因无法分辨使用哪份而编译报错

5.3 虚继承   virtual

        当使用virtual关键字修饰继承时,子类中多增加一个虚指针,用于指向父类内容

        当该子类被继承时,孙子类也会继承该虚指针,如果孙子类中有多个虚指针,则编译器会比较这些虚指针指向的父类内容是否是同一份,如果是,则只保留一份

总结:虚继承目的是为了解决孙子类中有多份相同的祖先类的问题

注意:有些人认为多继承是C++的缺陷之一,一般建议不使用多继承,一定不要设计成菱形继承,C++提供的解决方法是使用虚继承,而一些后面的编程语言没有多继承,例如JAVA

6 虚函数、虚函数表、虚指针、覆盖

6.1 虚函数

        当成员函数被virtual修饰后,就称为虚函数

6.2 虚指针

        有虚函数的类中会多一个虚指针(虚表指针)

6.2 虚函数表

        虚指针中记录的是一张表格的首地址,该表格中记录的是该类中所有虚函数的地址

        ((void(*)(void))(*(int*)*(int*)b))();// 调用的是虚函数表中的第一个函数 void func(void)

6.3 覆盖:(重写)

        当使用virtual修饰父类的成员函数时,父类中就会多一个虚表指针,子类会把父类中的虚表指针以及虚函数表一起继承过来,如果子类中有与父类虚函数同名的函数时,编译器会去比较这两个同名函数的格式,如果格式完全相同,那么会把子类中同名函数的地址覆盖子类中虚函数表中的同名父类虚函数的地址,这种情况就称为覆盖

        此时使用父类指针或引用指向子类对象时,调用父类的虚函数则会调用被覆盖后的子类的同名且格式相同的成员函数 

构成覆盖的必要条件:

① 子类public继承父类

② 父类中被覆盖的函数必须为虚函数

③ 子类中必须有与父类虚函数名字、返回值类型、参数列表、常属性都完全相同的成员函数

④ 返回值类型相同、或者如果子类成员函数的返回值可以向父类虚函数返回值类型进行隐式转换且具有继承关系,也可以构成覆盖

多态

1 什么是多态?

        多态指的是同一个指令的多种形态,当调用同一个指令时,能根据参数、环境不同做出相应的操作

        C++中根据确定执行哪个操作的时间点分成:编译时多态、运行时多态

1.1 编译时多态

        当调用重载函数时,编译器会根据参数的类型、个数等,在编译期间就能确定指定哪个版本的重载函数,属于编译时多态,还有模板技术等

1.2 运行时多态

        当子类覆盖了父类中的同名虚函数,然后用父类指针或引用访问虚函数时,它可能调用父类中的虚函数,也可能调用其它覆盖了虚函数的子类中的同名函数,具体调用哪个版本是根据父类指针或引用指向哪个对象而决定的,而这个父类指向哪个对象可以在运行时才能确定,因此这种就称为运行时多态

1.3 构成运行时多态的必要条件:

        ① 父子类中必须构成覆盖

        ② 运行时才能确定父类指针或引用访问的是哪个构成覆盖的子类或者是父类

1.4 虚构造与虚析构

1.4.1 虚构造

        构造函数不能是虚函数

        假设构造函数可以定义为虚函数,在实例化子类对象时,先执行子类构造函数的初始化列表,那么就会先根据继承表顺序执行父类的构造函数,此时父类构造函数为虚函数被子类构造函数覆盖,又变成执行子类的构造函数,导致进入死循环,因此编译器禁止把构造函数定义为虚函数

1.4.2 虚析构

        析构函数可以定义为虚函数

        当使用类多态时,通过父类指针或引用释放子类对象时,默认只会执行父类的析构函数,不会去执行子类的析构函数,但是在创建子类对象时,已经调用了子类的构造函数,如果不执行子类的析构函数,可能会导致内存泄漏。

        只有把父类的析构函数定义为虚函数(子类析构会自动覆盖,不关注名字是否相同),通过父类指针或引用释放子类对象时,就会先调用覆盖后子类的析构函数,而子类的析构函数执行完后,会自动调用父类的析构函数(对象销毁规则),因此不会导致内存泄漏

注意:当使用了多态,且子类的构造函数中申请了资源时,则父类的析构函数一定要设置为虚析构

1.5 纯虚函数、纯抽象类

1.5.1 纯虚函数

class Base
{
    public:
    virtual 返回值 函数名(参数列表) = 0;
};

        ① 纯虚函数的本意就是为了让子类来覆盖,所以纯虚函数不要去实现它

        ② 有纯虚函数的类不能创建该类的对象

        ③ 父类中有纯虚函数,子类必须覆盖,否则连对象都无法创建

        ④ 纯虚函数就是为了强制子类去覆盖,为了强制实现某些功能

        ⑤ 含有纯虚函数的类称为抽象类

        ⑥ 析构函数不能设置为纯虚函数

1.5.2 纯抽象类

        所有的成员函数都是纯虚函数,这种类称为纯抽象类,一般用于设置功能接口函数,也叫做接口类,它自己不实现具体功能文章来源地址https://www.toymoban.com/news/detail-476231.html

到了这里,关于C++基础篇:07 继承与多态的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】继承和多态

    继承机制是面向对象程序设计使代码可以 复用 的最重要的手段,它允许程序员在保持原有类特性的基础上进行 扩展 ,增加功能,这样产生新的类,称 派生类/子类 。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复

    2024年02月06日
    浏览(43)
  • C++ 中的继承和多态

    继承允许我们 依据一个类来定义另一个类 ,这使得创建和维护一个应用程序变得更容易。这样做也达到了重用代码功能和提高执行效率的效果。 派生类的成员可以直接访问基类的保护成员(protected),但不能直接访问基类的私有成员(private) 。不过需要注意的是,派生类

    2024年02月06日
    浏览(42)
  • c++面向对象之封装、继承、和多态

    把客观事物封装成类,而且可以把自己的数据和方法设置为只能让可信的类或者对象操作,对不可信的信息进行隐藏(利用public,private,protected,friend)实现 has-a :描述一个类由多个部件类构成,一个类的成员属性是另一个已经定义好的类。 use-a:一个类使用另一个类,通过类之间

    2024年02月02日
    浏览(53)
  • 【C# 基础精讲】继承、封装、多态

    继承(Inheritance)、封装(Encapsulation)和多态(Polymorphism)是面向对象编程中的三大核心概念,它们构成了面向对象编程的基础,有助于创建更加模块化、可扩展和可维护的代码。这三个概念在C#及其他面向对象编程语言中广泛应用,本文将详细解释这三个概念的含义、特点

    2024年02月12日
    浏览(40)
  • C++ 面向对象核心(继承、权限、多态、抽象类)

    继承(Inheritance)是面向对象编程中的一个重要概念,它允许一个类(称为派生类或子类)从另一个类(称为基类或父类)继承属性和方法。继承是实现类之间的关系,通过继承,子类可以重用父类的代码,并且可以在此基础上添加新的功能或修改已有的功能。 在C++中,继承

    2024年02月08日
    浏览(49)
  • 【C++】继承和多态、共有私有和保护、重写

    继承是一种机制,通过它 一个类可以从另一个类继承属性和方法 。派生类(子类)继承基类(父类)的成员函数和数据成员,并且可以在其基础上扩展自己的成员函数和数据成员。C++支持多重继承,即一个派生类可以同时从多个基类中继承。 多态是指 同一种操作作用于不同

    2024年02月03日
    浏览(40)
  • 什么是面向对象,它的三个基本特征:封装、继承、多态

    什么是面向对象思想?已经学完了java确不知道如何跟别人解释面向对象是什么意思这很常见。让我们一起来回顾下这个奇思妙想~ 现在越来越多的高级语言流行起来了,如大家耳熟能详的c++,python,java等,这些都是基于 面向对象 的语言 而最最基础的,学校必学的语言----c语

    2024年02月02日
    浏览(54)
  • 【Java0基础学Java第八颗】 -- 继承与多态 -- 多态

    通俗来说就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态 。 就比如打印机,彩色打印机和黑白打印机,打印出的效果一个是彩色,一个是黑白。 即: 同一件事情,发生在不同对象身上,就会产生不同的结果 。 在Java中要实现多态,

    2024年02月04日
    浏览(44)
  • C++ 第三弹继承和多态-类和对象

    目录 1.继承 1.1什么是继承? 1.2语法格式 1.3继承权限 1.4继承概念语法格式 1.5赋值兼容规则 1.6继承体系中的作用域 1.7在继承体系中的构造和析构 1.8静态成员继承 1.9友元的继承 1.10不同继承方式下子类的对象模型 1.11继承和组合 2.多态 2.1什么是多态 2.2多态的分类 2.3实现条件

    2024年02月10日
    浏览(33)
  • c++入门学习⑦——继承和多态(超级详细版)

    目录 前言 继承 继承是什么? 为什么会存在继承? 语法: 一些基本的定义: 三种继承方式: 对象模型 对于构造和析构的顺序 同名函数的处理方式 总结: 静态成员: 定义: 性质: 共享数据  编译阶段分配内存 类内声明类外初始化 静态成员函数 静态成员函数与普通成员

    2024年02月21日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包