细数继承与派生(纯干货推荐)1.0
目录
- 一、类与对象的基础
- 1、简单概念
- 2、类的类型
- ①、公有
- ②、私有
- ③、保护
- 4、扩展:(类和结构体的区别)
- 二、使用类和对象
- 方法一:
- 方法二:
- 方法三:
- 三、继承与派生
- 1、名称解释
- 2、单一继承
- ①、公有继承
- ②、私有继承
- ③、保护继承
- ④、总结
- 3、多重继承
- 4、注意事项
- ①、相互赋值
- ②、避免二义性
最近在学习C++面向对象设计,看似很基础的内容实际上有多知识点值得推敲。
学完类与对象,就很想写点东西来输出我的思考和学习的想法,也希望各位朋友一起多多交流,如果文章里有错误的地方请多多指正。
一、类与对象的基础
前言:
学习C,要有面向过程的设计思想。
学习C++,要有面向对象的设计思想。
1、简单概念
对象: 任何一个事物都可以看成一个对象,比如一个班级,一个学校,一篇文章等等。
对象包含两个要素:属性 和 行为。
举个栗子:我们把一个班级看做一个对象,那么班级里的人数,专业,平均成绩叫做属性(静态的)。班级上课,参加运动会等叫做行为(动态的)。一个对象一般是由一组属性和一组行为构成。
封装 :一般对象里的内容会涉及到秘密,在面对外人时。我们可以把对象里的部分内容盖起来不让外人看到。
举个栗子:班级期末考试,家长想知道班级里所有人的成绩(家长对班级这个对象进行访问/调用),但我们只告诉家长班级平均成绩,所有的同学的成绩都不对外公布(个人成绩进行封装)。相反,平均分就是属于大家都能看到/接触/调用的内容。
2、类的类型
①、公有
听名字就知道,这是个大家都能看得到或者接触得到的内容。
比如上个栗子中的班级平均分就属于公有部分,班级中的每位家长都可以看到。
class Student
{public:``````
}
②、私有
听名字就知道属于定义对象所拥有的部分,不能让外界看到或者解除(当然也会有例外,这里挖个坑)。把部分成员进行封装,防止外人看到。
上个栗子中对应的是班级里每位同学的成绩。
class Student
{private:``````
}
③、保护
首先一个问题,保护类型和私有类型有什么区别?
这里我们先做个简单的介绍:
私有和保护的成员函数和数据只能被本类中的其他成员函数所调用,而不能被类外调用。
而保护的功能在继承与派生中更能体现出来,
当然也有例外的情况发生。同私有类型一样,挖个坑。 写完例外情况(友元),我会在此处做个文章链接。
class Student
{protected:``````
}
4、扩展:(类和结构体的区别)
先上两种定义:(Student为例)
///class
class Student
{private:int num;char sex:string name;public:void display();
};
///struct(C)
struct Student
{int num;char sex:string name;
}stu;void display(int num,char sex,string name);
补充一个小知识:C++在设计的时候就以兼容C,但又不是完全简单的继承C,同时还要有自己的特点为原则进行开发。
最明显的就是struct中没有private和public,想给student添加什么属性直接写进去就完事了。
class不同,除了想把属性加进去外,还要考虑这个属性要不要让别人看到。想让别人能看到,加入public中。不想让别人看到就加入private中。
举个栗子:
如果把struct比作一家新百伦鞋店,那么这家店就属于通透型的,穿鞋换鞋坐在沙发板凳上就可以完成,无需试衣间。所有的地方一览无余。
class更像是含有试衣间的优衣库。挑选衣服的时候大家都能看到,但是试衣服的时候就必须要去试衣间里。我想没有多少人在换衣服的时候被别人看到吧?
以上内容引用于比较C中的struct和C++中的class。
而在C++中对于struct的用法进行了升级:
///struct(C++)
struct Student
{private:int num;char sex:string name;public:void display();
};
可见C++中使用struct也可以像class一样对成员进行public或private分类。
此时他们的区别就是对于未声明的成员进行默认分类。
///class
class Student
{int num;char sex:string name;///三种成员被默认为private类型///进行类内访问,类外不能访问
};
///struct(C++)
struct Student
{int num;char sex:string name;///三种成员默认为public类型///类内类外均可以访问
};
二、使用类和对象
设计好了我们所需要的类,接下来就是定义对象。
方法一:
class Student stu1,stu2;///class Student合起来作为一个整体类名,来定义对象Student stu1,stu2;///或者直接使用Student定义对象,与结构体定义对象相同
方法二:
class Student
{private:int num;char sex:string name;public:void display();
}stu1,stu2; ///与结构体定义相同
方法三:
class
{private:int num;char sex:string name;public:void display(); ///这可以不通过类名直接定义对象,但是不推荐使用。结构体中也是这样
}
三、继承与派生
1、名称解释
构造函数
我们通过构造函数来使对象的属性进行初始化。如果想添加初始值,可以手动设置。反之可以交给编译器自动指定默认值。
建立好类之后,一般我们需要对其进行初始化。这是为什么呢?就像我们注册某个网站时,填写好注册名称,密码进行默认选择一样。在登录之后会要求进行修改密码以保证登录的私密性。
析构函数
如果说构造函数是为了方便用户对类进行初始化。那么析构函数就是在你完成所有程序功能,帮你进行收尾后勤工作。此时你不用管设置了多少个属性,开辟了多少内存空间。只要析构函数执行,就能帮你完成一切。我更愿意称之为妈妈式的程序。
继承
聊下继承(inheritance),这个单词也有遗传的意思。那么就看出来继承或遗传的东西有前辈的内容,也会有自己独有/新添加的内容。
派生
在原来已经存在的类的基础上建立一个新的类。这个过程叫做父类派生出子类。
子类继承了父类的成员内容,也会存在着属于自己新添加的成员内容。
基类
又名:父类。
已经存在设计好的类型。(与下面的派生类做对应记忆)
派生类
又名:子类。
通过继承之前设计好的类,得到新建立的类。
2、单一继承
派生类中的成员包括了从基类继承过来的成员和自己新增加的成员两部分。
①、公有继承
对基类成员内容通过公有方式继承得到的派生类。
///基类
class Student
{ int num; //默认为private类型char name[30];char sex;public: void display( ) //对成员函数display的定义{cout<<"num: "<<num<<endl;cout<<"name: "<<name<<endl;cout<<"sex: "<<sex<<endl; }
};
///派生类
class Student1: public Student//声明基类是Student
{private:int age; //新增加的数据成员string addr; //新增加的数据成员
public:void display_1( ) //新增加的成员函数{ cout<<"age: "<<age<<endl; cout<<"address: "<<addr<<endl;}
};
补充: 在建立派生类的过程中,基类不会做任何改变。派生类除了从基类中得到成员内容,也可以重新定义属于自己的变量与函数。
例如:父类对象为“马”,含有的成员变量有马的性别,年龄等。我们可以对马进行更加细致的划分,建立派生类汗血宝马(添加新的成员变量:跑步里程),蒙古马(添加新的成员变量:毛发长度),大宛马(添加新的成员变量:一顿能吃多少个馒头)等等。这样就就与派生类就与基类有了分别。
那么通过公有继承的方式,可以从派生类中访问基类的内容吗?当你脑海中蹦出这个问题时就说明已经学会举一反三了。
公有派生时,基类中的所有成员在派生类中的保持各个成员的访问权下,如下图
另外上个图能让大家更好理解
上述图片中(a)为基类(父类),(b)为派生类(子类),(c)是整理过后的派生类。可以看出通过公有继承图(c)中已经没有了类A的private变量k。这是因为通过公有继承,对父类的私有变量已经进行了封装,无法在派生类中访问(不可见)。但是可以通过类A中的成员函数引用到private中的k。
通过公有继承中,派生类想对基类中的private成员不可以引用,那我们就是想引用怎么办?
这里就是前面说的特例——友元。
挖个坑!!!
下面是个公有继承的小实例,有时间的读者可以认真看一下,代码很简单。
#include <bits/stdc++.h>using namespace std;class Student
{ int num = 12138; //默认为private类型char name[30] = "ZhangSan" ;char sex = 'M';public:void display( ) //对成员函数display的定义{cout<<"num: "<<num<<endl;cout<<"name: "<<name<<endl;cout<<"sex: "<<sex<<endl; }
};class Student1: public Student//声明基类是Student
{private:int age = 18; //新增加的数据成员string addr = "China"; //新增加的数据成员
public:void display_1( ) //新增加的成员函数{ cout<<"age: "<<age<<endl;cout<<"address: "<<addr<<endl;}
};
///ac不知深
int main()
{Student stu1;Student1 stu2;cout << "stu1直接输出" << endl;stu1.display();cout << "stu2直接输出" << endl;stu2.display_1();cout << "stu1通过访问stu1输出" << endl;stu2.display();return 0;
}
②、私有继承
对基类成员内容通过私有方式继承得到的派生类。基类中public成员和protected成员会在派生类中都变成私有的。但是在派生类中仍然可以直接使用这些成员。基类中的private成员在派生类中依然不能直接使用。
///基类
class Student
{ int num; //默认为private类型char name[30];char sex;public: void display( ) //对成员函数display的定义{cout<<"num: "<<num<<endl;cout<<"name: "<<name<<endl;cout<<"sex: "<<sex<<endl; }
};
///派生类
class Student1: private Student//声明基类是Student
{private:int age; //新增加的数据成员string addr; //新增加的数据成员
public:void display_1( ) //新增加的成员函数{ cout<<"age: "<<age<<endl; //引用派生类的私有成员cout<<"address: "<<addr<<endl; //引用派生类的私有成员} void get_value_1(){cin >> num >> name >> sex ; //输入派生类数据}
};
和公有继承是的原理都是相似的。
私有派生时,基类中的所有成员在派生类中的保持各个成员的访问权下,如下图
同样上个图让大家印象更深刻
上述图片中(a)为基类(父类),(b)为派生类(子类),(c)是整理过后的派生类。可以看出通过私有继承图(c)中已经没有了类A的private变量k。这是因为通过私有继承,对父类的私有变量已经进行了封装,无法在派生类中访问(不可见)。同时,类A中的public与protected类型均转变为类B的private类型。
由此我们可以看到,私有继承似乎更霸道些。对于基类继承来的成员,派生类外是都不可以访问的。这种继承方式更倾向于保护隐私内容,不想让其他程序员知道我们自己定义的内容。
下面这个实战小例子,通过私有继承,可以很好与公有继承实例做个比较——无法通过类外访问私有继承的成员函数。
#include <bits/stdc++.h>using namespace std;class Student
{ int num = 12138; //默认为private类型char name[30] = "ZhangSan" ;char sex = 'M';public:void display( ) //对成员函数display的定义{cout<<"num: "<<num<<endl;cout<<"name: "<<name<<endl;cout<<"sex: "<<sex<<endl; }
};class Student1: private Student//声明基类是Student
{private:int age = 18; //新增加的数据成员string addr = "China"; //新增加的数据成员
public:void display_1( ) //新增加的成员函数{ cout<<"age: "<<age<<endl;cout<<"address: "<<addr<<endl;}
};
///ac不知深
int main()
{Student stu1;Student1 stu2;cout << "stu1直接输出" << endl;stu1.display(); ///可以通过stu1直接访问基类cout << "stu2直接输出" << endl;stu2.display_1(); ///可以通过stu2直接访问派生类///cout << "stu1通过访问stu1输出" << endl;///stu2.display(); //本语句错误,无法通过stu2访问基类函数return 0;
}
③、保护继承
保护成员和私有成员在基类外都是不能被访问的,可以认为保护成员对类来说是私有的。但是保护成员可以被派生类的成员函数引用。这是两者比较明显的区别。
大家看到这个图一定觉得很迷惑,这个图明明和私有继承是一样的啊?
没错,但是protected 成员是一种具有血缘关系内外有别的成员。它对派生类的对象而言,是公开成员,可以访问,对血缘外部而言,与私有成员一样被隐蔽。但事无绝对,这里再一次挖个坑——友元。
在举个栗子,private更像是你们家的存折户口本房产证等,一般都由父母(父类可以访问)放在比较隐蔽的地方。即使是作为孩子的你(派生类)也不知道(无法访问),更不用说你的邻居朋友(类外无法访问)了。protected更像是你父母抽屉里的指甲剪,父母(父类可以访问)知道在哪,你也知道在哪(派生类可以访问)。但是朋友邻居(类外无法访问)就不知道在哪里。
还是迷迷糊糊的朋友直接看下面一张图!!!
下面一张图给你解释清楚!!!
类A分别通过private和protected继承得到B和C,再同时public继承得到B1和C1。
这个时候私有继承和公有继承的区别就显现出来了:
B1无法访问A中的public与protected成员;
C1可以访问A中的public与protected成员
接下来简单做个总结比较:
保护继承 | 私有继承 |
---|---|
public: (变为保护)在派生类中使用,类外不可使用 | public: (变为私有)在派生类中使用,类外不可使用 |
protected: (变为私有)在派生类中使用,类外不可使用 | protected: (变为私有)在派生类中使用,类外不可使用 |
private: 不能在派生类中和类外使用 | private: 不能在派生类中和类外使用 |
来个实战小例子
#include <bits/stdc++.h>using namespace std;class Student
{protected:int num;char name[30];char sex;public:///基类无公用成员
};class Student1: protected Student//声明基类是Student
{private:int age; //新增加的数据成员string addr; //新增加的数据成员
public:void get_value1(){cin >> num >> name >> sex; //输入保护基类数据成员cin >> age >> addr; //输入派生类数据成员}void display_1( ) //新增加的成员函数{cout<<"num: "<<num<<endl; //引用基类的保护成员cout<<"name: "<<name<<endl; //引用基类的保护成员cout<<"sex: "<<sex<<endl; //引用基类的保护成员cout<<"age: "<<age<<endl; //引用派生类的私有成员cout<<"address: "<<addr<<endl; //引用派生类的私有成员}
};
///ac不知深
int main()
{Student1 stu1; //stu1是派生类Student1类的对象stu1.get_value1(); //get_value1是派生类中的公有成员函数,输入数据stu1.display_1(); //display1是派生类中的公有成员函数,输出数据return 0;
}
④、总结
最后我们做一个基类成员在派生类中的访问属性比较
在基类的访问属性 | 继承方式 | 在派生类中的访问属性 |
---|---|---|
private(私有) | public(公有) | 不可访问 |
private(私有) | private(私有) | 不可访问 |
private(私有) | protected(保护) | 不可访问 |
public(公有) | public(公有) | public(公有) |
public(公有) | private(私有) | private(私有) |
public(公有) | protected(保护) | protected(保护) |
protected(保护) | public(公有) | protected(保护) |
protected(保护) | private(私有) | private(私有) |
protected(保护) | protected(保护) | protected(保护) |
派生类中的访问属性有四种:不可访问,public,private,protected。
①不可访问,派生类内类外都不能访问;
②public,派生类内类外都可以访问;
③private,派生类内可以访问,派生类外不能访问;
④protected,派生类内可以访问,派生类外不能访问,其新派生出的下一代的派生类可以访问。
3、多重继承
前面讨论的是单一继承。实际上,常常有一个派生类有两个或多个基类,派生类从两个或多个基类中继承所需的属性。比如,你的白天在公司扮演者普普通通的码农,晚上扮演着媳妇的好老公。你的身份就可能需要继承多个基类才能更好更完善的刻画出你的形象。代码更好的向前一步发展,我们需要多重继承。
这里我觉得没有太多难点,只要单一继承弄明白了多重继承分分钟就ok!
class D: public A, protected B, private C
{ ....//派生类中新增加成员
};
这里就直接给大家一个简单的例子进行学习
class A
{public: int x;void Show(){cout <<"x="<<x<<'\n';}
};class B
{public: int y;void Show(){cout <<"y="<<y<<'\n';}
};class C:public A,public B
{public: int y; //类B和类C均有y的成员
};void main(void)
{ C c1; c1.x=100;c1.y=200; //给派生类中的y赋值c1.B::y=300; //给基类B中的y赋值c1.A::Show(); c1.B::Show(); //用作用域运算符限定调用的函数cout <<"y="<<c1.y<<'\n'; //输出派生类中的y值cout <<"y="<<c1.B::y<<'\n'; //输出基类B中的y值
}
4、注意事项
①、相互赋值
这里其实真正的叫法是基类与派生类的转换。
这个篇幅太长(主要是我懒),我们放在下篇文章继续更新!
②、避免二义性
多种继承能够更好地处理比较复杂的问题。比如一个在职的研究生老师张三,张三属于教师类,属于研究生类,也属于一个人类(废话hhhh),我们做个简单的定义。
class Teacher //教师
{public:void display();
protected:string name; //姓名int age; //年龄string title; //职务};class Student
{public:void display1();
protected:string name; //年龄char sex; //性别float score; //分数
};class Graduate:public Teacher,public Student
{public:void show();
private:float wage; //补贴
};
///ac不知深
这里我们看到在类Teacher和类Student中都有姓名成员,如果只是单纯的继承会导致Graduate中存在两个name函数,初始化赋值时一定会报错。具体怎么解决这个问题,麻烦各位读者点赞和关注,我会尽快更新这部分的知识并在下面放上链接!
如果有帮助,可以一键三联呀!!!
细数继承与派生(纯干货推荐)1.0相关推荐
- CSDN光合计划-纯干货-推荐几个python全系列学习教程
前言 踏着春天的脚步我们迎来了2021年,经历过2020年技术裁员的你还在守着混吃等死的日子吗?为未来的自己留一条退路!想提升技术又不想报高昂费用的培训班,那么下面这些会是你不错的一个选择,需要的小伙 ...
- 大数据数仓建模 - 维度建模 实战及思路过程 (两年数仓建模经验 纯干货)
数仓维度建模 维度建模方法论: 维度建模 是以业务过程为驱动 先确定某些业务过程 围绕业务过程去建立模型 通常采用自底向上的方法 从明确关键业务过程开始 再到明确粒度 再到明确维度 最后明确事实 在 ...
- CSDN光合计划-纯干货-推荐几个Java全系列学习教程
前言 踏着春天的脚步我们迎来了2021年,经历过2020年技术裁员的你还在守着混吃等死的日子吗?为未来的自己留一条退路!想提升技术又不想报高昂费用的培训班,那么下面这些会是你不错的一个选择,需要的小伙 ...
- 好物推荐文案怎么写吸引人?纯干货
互联网上充斥着各种各样好物种草文,一不小心就跌入了软文的圈套中,好物推荐文案写得好,流量绝对少不了. 好物推荐文案怎么写吸引人?通过整理总结上百篇爆款种草文案,总结出一套超实用的文案写作妙招!纯干货! ...
- 前端面试题汇总(JavaScript面试纯干货)
前端面试题汇总(JavaScript面试纯干货) 1 闭包 闭包就是能够读取其他函数内部变量的函数 闭包是指有权访问另⼀个函数作⽤域中变量的函数,创建闭包的最常⻅的⽅式就是在⼀个函数内创建另⼀个函数, ...
- 2021年超详细的-Android超神学习路线总结--纯干货分享(字节,阿里,腾讯大牛联合打造)
前言 2021年秋招没有找到满意工作的童鞋,考研结果不理想的童鞋,留学生回国的童鞋们,都开始准备2021年的春招了,如果想从事Android开发工作,可以参考本文. 本文整理了Android开发的学习 ...
- class转java_[拒绝套路,纯干货]这一百多道 Java 基础问题你掌握了吗?
码农每日一题长按关注,工作日分享一些技术知识点. [每日一题]Java 基本数据类型基础面试题 [每日一题]Java 包装类型装箱拆箱基础面试题 [每日一题]Java 字符串(Part 1)相关面试题 ...
- python代码示例图形-纯干货:手把手教你用Python做数据可视化(附代码)
原标题:纯干货:手把手教你用Python做数据可视化(附代码) 导读:制作提供信息的可视化(有时称为绘图)是数据分析中的最重要任务之一.可视化可能是探索过程的一部分,例如,帮助识别异常值或所需的数据转 ...
- 程序员,想要彻底弄懂Redis,这15点你一定要明白~(纯干货)
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:Java实现QQ登录和微博登录个人原创+1博客:点击前往,查看更多 作者:耿直的小码农 来源:https://s ...
- 细数sass安装中遇到的坑
前言: 前两天打算清理电脑的时候,遇到了一点特殊的问题,打算重装一些东西,其中就有我一直用的顺手的SASS预编译工具. 但是在重装的时候,我发现我居然不会用了??? 靠,要不是我用了半年的Sass,我 ...
最新文章
- 自定义GridView 介绍
- java版selenium_Selenium3.0-Java版(共61节)
- Python Pycharm创建虚拟环境
- redis 编译/调试
- 开心--开始--开发--开心
- arcgis for flex api version3.7 教程:7.使用Directions查询路线(最短路径分析)
- 卡耐基梅隆大学 计算机信息管理,CMU-喜报!G同学成功收到2017-Fall 卡耐基梅隆大学 计算机信息技术硕士AD一枚...
- C语言基础之排列组合数字
- android获取app使用时间,android如何获取系统里各个应用的使用时间
- 去掉input自动填充的黄色背景
- 使用cubemx建立一个内部flash虚拟一个U盘的工程
- FPGA_Verilog学习之旅(3)---VGA贪吃蛇游戏
- 深入剖析Kubernetes--第五章:声明式API与Kubernetes编程范式
- 341.基于高通量测序的微生物组研究技术简介
- Java中csv文件读写分析
- 【千律】OpenCV基础:图像阈值分割 -- 自适应阈值分割 -- 代码实现
- Neural-Motifs 运行环境配置
- 小白程序员怎么由量变到质变写出高质量代码
- win7镜像下载和安装vm教程
- 为什么设置不了这是一台家用计算机,图文演示win10专业版更改不了这是一台家庭计算机的详尽处理步骤...
热门文章
- Double得有效位
- 应届生web前端面试题_Web前端初学者(应届生)面试攻略
- ios怎么引入masonry_iOS-Masonry的简单使用
- linux的使用 --- 安装node和express
- 主从同步redis和mysql的区别_mysql主从复制、redis基础、持久化和主从复制
- 函数式接口,方法引入
- sqlite3 加密版本 下载_制作Sqlcipher+SM4加密的framework包(OC)
- gcc/g++ 如何支持c11/c++11标准编译
- SpringMVC项目搭建及遇到的问题
- 前端面试总结--数据结构与算法五