0


植物大战 继承——C++

“物是人非事事休, 欲语泪先流”

猛戳订阅🍁🍁 👉 [C++详解专栏] 👈 🍁🍁

这里是目录

一、继承的概念以及定义

继承机制是面向对象程序设计使得代码可以复用的重要手段,它允许程序员在保持原有类的特性的基础上进行扩展,增加功能,这样产生新的类,为派生类

继承呈现了面向对象程序设计的层次结构。提现到了由简单到复杂的认知过程。

以前接触的复用都是函数复用,继承是类设计层次的复用

//父类classA{public:voidPrint(){
        cout <<"_a"<< endl;}protected:int _a;};//子类classB:publicA{protected:int _b;};

注意:实例化出来的对象里面不存方法,只存成员变量。

1.继承方法

重点:
1.在实际中父类成员基本都是保护和共有

2.protected和private成员对于基类都是一样的。
3.protected成员对于子类来说是可以使用的,而private成员
不可以用
保护继承是在类内可以访问,在类外不能访问。

私有继承在派生类中都是不可见。但不可见得意思是:私有的成员变量在子类里面,但是语法限制你不能访问

访问的权限是:保护继承,公有继承,取小的那个。

二、基类和派生类对象赋值转换

派生类对象可以赋值给基类的对象,指针,和基类的引用。这里有个形象的说法叫做切割或者切片。(也叫作向上转换)

普通对象之间赋值会产生临时对象。但这个过程是天然的,没有类型转换。(这个在C++中很重要)这个叫做赋值兼容转换

注意
引用的是子类的一部分别名。

指针是指向父类的一部分

三、继承中的作用域

基类 和 派生类 都会形成独立的作用域。

2.隐藏

隐藏:在不同的中会有相同的名称的变量。这时子类会对父类进行隐藏,也叫作重定义。

隐藏的话想访问父类的变量,则需要加**类域限定符::**。
最好不要用重名的变量。

成员函数也会重名,成员函数和成员变量一样。都会构成隐藏
只要成员函数名相同就会构成隐藏
但有一点需要注意:函数重载要求在同一作用域。在同一作用域才探讨重载。重载需要函数名相同,参数不同

但隐藏是在不同的作用域!

四、派生类的默认成员函数

默认的意思,就是我们不写,编译器自动生成的构造函数。

子类构造函数原则
1.先调用父类的构造函数,来初始化继承自父类的成员。
2.然后再初始化自己的成员。

析构、拷贝构造,赋值重载也类似。也是以上的原则。

父类的成员一定要调父类的构造函数初始化。初始化列表就是调用默认构造函数的地方。

1.拷贝构造

先在初始化列表调用父类的默认构造函数,再初始化子类的成员。

2.赋值重载拷贝

注意子类的operator=和父类的构成了隐藏,要记得加类域限定符::

3.析构函数

析构函数比较特殊。这是C++特殊的地方
析构函数不用调用父类的析构函数。这里比较特殊,构成了隐藏。

父类的析构函数和子类的析构函数构成了隐藏关系

因为1.由于多态的需要,析构函数统一处理成了destructor().
2.为了保证析构顺序,会先调用子类,再自动调用父类的析构函数,不需要我们显式的调用。

这跟我们的存储的顺序有关,先定义的后析构。

4.如何设计一个不能被继承的类?

不能创建子类的对象,因为创建子类的对象,就要调用父类的构造函数。但是父类的构造函数是一个私有的。所以这个类不能被继承。

//父类classA{private:A(){}};//子类classB:publicA{};intmain(){
    B b;//错误。不能创建对象return0;}

五、继承与友元

友元不能继承,友元的关系不能继承下来。

你是父亲的朋友,但不一定是儿子的朋友。

六、继承的静态成员变量

父类的静态变量子类都会继承下来。

C++静态成员变量需要在类外定义和初始化。

//父类构造函数classPerson{public:Person(){++_count;}protected:
    string _name;//静态成员变量public:staticint _count;};//C++静态成员变量一定要在类外进行定义和初始化。int Person::_count =0;classStudent:publicPerson{protected:int _stuNum;};classGraduate:publicStudent{protected:
    string _course;};intmain(){
    Student s1;
    Student s2;
    Student s3;

    Graduate s4;
    cout <<"人数:"<< Person::_count << endl;
    Student::_count =0;
    cout <<"人数:"<< Person::_count << endl;return0;}

七、多继承(了解)

单继承:一个子类只有一个直接父类叫做单继承。

多继承:一个子类有两个或两个以上的直接父类就叫做多继承。
在这里插入图片描述

1.菱形继承

菱形继承是多继承的一种特殊情况。它会产生数据冗余,和二义性,子类会同时继承两个父类的两份数据,造成了二义性。

因为这个缺点,所以java是没有多继承的

2.虚继承

虚继承可以说是C++的缺陷了。

怎么解决菱形继承这个问题呢?
这个就叫做虚继承,在腰部的位置加上关键字virtual

这时候vs的监视窗口看到的东西已经不准了。

3.对象模型

普通多继承的对象模型。
在这里插入图片描述

虚继承
在这里插入图片描述多了两个指针区域,每个指针四个字节,用来存储距离A位置的偏移量,用来计算A的位置。

重点理解就是,B和C有个A但是A没有存在B和C的位置,所以需要通过偏移量找到A。

A就叫做虚基类。
存放指针的区域的指针,叫做虚基表指针。

为什么要存储A的偏移量,因为d赋值给b,在赋值的时候,需要找A的位置,需要切片,切片需要通过偏移量计算A的位置。

八、面向对象三大特性

面向对象不止三大特性:还有java的反射、抽象

什么是封装、继承、多态?这个问题是没有标准答案的。

1.封装

主要是和C语言对比,C语言数据和方法是分开的,而C++是放在一起的。
例如:1.C语言的Stack和C++的Stack对比。
狭义的:
封装更好。来讲:封装指的是 访问限定符+类的封装。

广义的封装:例如封装了容器底层结构。封装其实也是一种隐藏

2.迭代器的设计:
如果没有迭代器,容器的访问只能暴露底层结构。暴露的话,使用复杂,使用成本很高对使用者的要求也极高。你得懂二叉树,链表。假如有迭代器的话,使用非常的方便!

封装的好处:在不暴露底层结构情况下,提供统一的访问容器的方式。

3.优先级队列的设计。–适配器模式。

假如不用适配器,就要自己写一个stack,queue,priority_queue。

2.继承

继承的本质就是:类设计角度的复用。
继承就是在更高的维度来设计类。

继承是类与类之间的关系。

有些数据和方法是每个角色都有的。有些是独有的。都有的就是重复的。

继承就是把那些每个角色都有的数据和方法提取出来。然后做成一个类。

其他独立的数据和方法就可以单独作为一个类来继承。

标签: c++ java 开发语言

本文转载自: https://blog.csdn.net/qq2466200050/article/details/127062817
版权归原作者 乔 巴 所有, 如有侵权,请联系我们删除。

“植物大战 继承&mdash;&mdash;C++”的评论:

还没有评论