😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰:
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、继承的定义
- 🎄三、派生类(子类)继承了什么
- ✨3.1 派生类从基类继承了哪些东西
- ✨3.2 继承的东西怎么使用
- 🎄四、派生类对象的创建、销毁
- 🎄五、
- 🎄六、
🎄一、概述
继承的概念:
- 继承(inheritance)机制是面向对象程序设计中使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。
- 继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用
通过继承可以完成的一些工作:
- 1、可以在己有类的基础上添加功能。 例如, 对于数组类, 可以添加数学运算。
- 2、可以给类添加数据。 例如, 对于字符串类, 可以派生出一个类, 并添加指定字符串显示颜色的数据成员。
- 3、可以修改类方法的行为。
按照继承权限区分,有公开继承、保护继承、私有继承三种方式。
按照继承的直接基类个数区分,有单继承、多重继承两种方式。
🎄二、继承的定义
通过继承 ( inheritance ) 联系在一起的类构成一种层次关系。通常在层次关系的根部有一个基类(base class),其他类则直接或间接地从基类继承而来,这些继承得到的类称为派生类(derived class)。基类负责定义在层次关系中所有类共同拥有的成员, 而每个派生类定义各自特有的成员。
派生类必须通过使用**类派生列表(class derivation list)**明确指出它是从哪个(哪些)基类继承而来的。
类派生列表的形式是:首先是一个冒号,后面紧跟以逗号分隔的基类列表,其中每个基类前面可以有访问说明符。
访问说明符有三种:pulbic(公有继承)、protect(保护继承)、private(私有继承)。
类派生列表也可以有多个基类,如:class CDog : public CAnimal, public CFriend
下面用代码演示一下继承的过程:
class CAnimal{
public:CAnimal(){sprintf(m_name, "Ainmal");}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}
private:char m_name[64];
};class CDog : public CAnimal{};
is-a
:我们这里使用的是 公有继承,它需要遵循is-a
的关系,就是派生类 is a 基类
,可以表示成派生类 是 基类
,例如“狗 是 动物”。按照这个关系,我们不能在 动物 和 苹果 之间使用公有继承。派生类对象也是一个基类对象,可以对基类对象执行的任何操作,也可以对派生类对象执行。
🎄三、派生类(子类)继承了什么
继承完之后,那么派生类继承了哪些东西?这些东西怎样使用呢?这个小节,我们来学习这两个问题的答案。
✨3.1 派生类从基类继承了哪些东西
派生类继承了基类的 数据成员 和 大部分的函数成员,而基类的 构造函数、析构函数、赋值运算符函数
不会被派生类所继承。
下面修改一下上面的代码,演示派生类继承了父类的数据成员。
// 22_Inheritance.cpp
// g++ 22_Inheritance.cpp
#include <iostream>
#include <stdio.h>
#include <string.h>using namespace std;class CAnimal{enum{NAME_LEN=64};
public:CAnimal(){sprintf(m_name, "Ainmal");}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}
private:char m_name[NAME_LEN];
};class CDog : public CAnimal{
private:int m_hairColor; // 毛发颜色
};int main ()
{CAnimal animal;cout << "sizeof(animal)=" << sizeof(animal) << endl;CDog dog;cout << "sizeof(dog)=" << sizeof(dog) << endl;return 0;
}
运行结果如下:
从结果来看,派生类CDog 比基类CAnimal 多了 4 个字节。这4个字节刚好是一个int型,也就是派生类多的 m_hairColor 成员。而成员函数也是被继承的,但成员函数并不会放在类对象的内存中,而是放在程序的代码段。打印类对象大小只会打印该对象的数据成员总和。
✨3.2 继承的东西怎么使用
派生类继承的成员并不是可以随意地访问,跟继承时使用的 访问说明符 以及该成员在 基类中的访问权限 有关。
按照访问说明符的不同,可以分为public继承、protected继承、private继承
,它们从基类继承到的成员访问权限如下表:
类成员\继承方式 | public继承 | protected继承 | private继承 |
---|---|---|---|
基类的public成员 | 派生类的public成员 | 派生类的protected成员 | 派生类的private成员 |
基类的protected成员 | 派生类的protected成员 | 派生类的protected成员 | 派生类的private成员 |
基类的private成员 | 在派生类中不可见 | 在派生类中不可见 | 在派生类中不可见 |
从表格可以得出下面几个结论:
1、基类的私有成员,在派生类无法访问,只能通过基类的公有成员函数去访问。
2、基类的公有成员、保护成员,可以在派生类成员函数直接访问。
3、公有继承中,基类的公有成员、保护成员在派生类中也分别是公有、保护。
4、保护继承中,基类的公有成员、保护成员在派生类中都是保护的。
5、私有继承中,基类的公有成员、保护成员在派生类中都是私有的。
综上所述,派生类继承到的东西,并不是可以随意使用,而是按照上面表格和结论去使用。下面用代码演示怎样使用。代码使用了公有继承,基类的公有成员将成为派生类的公有成员;基类的私有部分也将成为派生类的一部分,但只能通过基类的公有和保护方法访问。
// 22_Inheritance1.cpp
// g++ 22_Inheritance1.cpp
#include <iostream>
#include <stdio.h>
#include <string.h>using namespace std;class CAnimal{enum{NAME_LEN=64};
public:CAnimal(){sprintf(m_name, "Ainmal");}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}void SetName(const char *name)// 修改私有成员 m_name{int len = strlen(name) > NAME_LEN ? NAME_LEN : strlen(name);memset(m_name, 0, sizeof(m_name));strncpy(m_name, name, len);}const char *GetName(){return m_name;}
private:char m_name[NAME_LEN];
};class CDog : public CAnimal{
public:enum{HAIR_BLACK, HAIR_WHITE};CDog(){m_hairColor = HAIR_BLACK;//sprintf(m_name, "Dog"); // 报错,基类私有成员在派生类无法访问。}
private:int m_hairColor; // 毛发颜色
};int main ()
{CAnimal animal;animal.run();CDog dog;dog.run();CDog dog1;dog1.SetName("dog1");dog1.run();return 0;
}
运行结果如下,代码演示了公有继承,派生类无法访问基类的m_name,但可以通过基类的公有函数SetName去修改m_name:
🎄四、派生类对象的创建、销毁
我们定义了一个派生类,大概率是需要用到这个派生类的对象的,那么派生类对象是怎样创建、销毁的呢?
创建派生类对象的几个要点:
1、派生类没有继承基类的构造函数。
2、创建派生类对象时,程序会先创建派生类对象的基类部分,所以,会先调用基类的构造函数,再调用派生类构造函数。
3、如果没有显式地调用基类构造函数,那么程序会自动调用基类的 无参构造函数 来创建派生类对象的基类部分。
4、如果要显式调用基类构造函数,为了保证先创建基类部分,需要在派生类构造函数的 成员初始化列表 去调用。
5、一般情况下,让基类构造函数初始化基类部分,派生类构造函数初始化派生类新增的数据成员。
派生类对象的销毁
派生类对象的销毁时,会先调用派生类的析构函数,再调用基类的析构函数。这个顺序与创建时相反。
🌰举例子:
// 22_Inheritance2.cpp
// g++ 22_Inheritance2.cpp
#include <iostream>
#include <stdio.h>
#include <string.h>using namespace std;class CAnimal{enum{NAME_LEN=64};
public:CAnimal() // 无参构造{sprintf(m_name, "Ainmal");cout << "Calling CAnimal(): this=" << this << endl;}CAnimal(char *name){int len = strlen(name) > NAME_LEN ? NAME_LEN : strlen(name);memset(m_name, 0, sizeof(m_name));strncpy(m_name, name, len);cout << "Calling CAnimal(char*): this=" << this << endl;}~CAnimal() // 无参构造{cout << "Calling ~CAnimal(): this=" << this << endl;}void run(){cout << "my name is "<< m_name <<", Animal run" << endl;}
private:char m_name[NAME_LEN];
};class CDog : public CAnimal{
public:enum{HAIR_BLACK, HAIR_WHITE};CDog(){cout << "Calling CDog(): this=" << this << endl;m_hairColor = HAIR_BLACK;}CDog(int color, char* name) : CAnimal(name){cout << "Calling CDog(int, char*): this=" << this << endl;m_hairColor = color;}~CDog(){cout << "Calling ~CDog(): this=" << this << endl;}
private:int m_hairColor; // 毛发颜色
};int main ()
{CDog dog;dog.run();cout << endl;CDog dog1(CDog::HAIR_BLACK, (char*)"dog1");dog1.run();cout << endl;return 0;
}
运行结果:
🎄五、
🎄六、
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁