黑马程序员C++类和对象【6】—— 继承(一文万字带你搞懂C++继承 —— 你还不知道怎么学C++继承吗?不知道虚继承底层原理吗?)(1)

简介: 黑马程序员C++类和对象【6】—— 继承(一文万字带你搞懂C++继承 —— 你还不知道怎么学C++继承吗?不知道虚继承底层原理吗?)(1)

 

继承是面向对象三大特性之一

有些类与类之间存在特殊的关系,例如下图中:

我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。


这个时候我们就可以考虑利用继承的技术,减少重复代码。

继承的基本语法

例如我们看到很多网站中,都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同


接下来我们分别利用普通写法和继承的写法来实现网页中的内容,看一下继承存在的意义以及好处

普通实现:

//Java页面
class Java 
{
public:
  void header()
  {
    cout << "首页、公开课、登录、注册...(公共头部)" << endl;
  }
  void footer()
  {
    cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
  }
  void left()
  {
    cout << "Java,Python,C++...(公共分类列表)" << endl;
  }
  void content()
  {
    cout << "JAVA学科视频" << endl;
  }
};
//Python页面
class Python
{
public:
  void header()
  {
    cout << "首页、公开课、登录、注册...(公共头部)" << endl;
  }
  void footer()
  {
    cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
  }
  void left()
  {
    cout << "Java,Python,C++...(公共分类列表)" << endl;
  }
  void content()
  {
    cout << "Python学科视频" << endl;
  }
};
//C++页面
class CPP 
{
public:
  void header()
  {
    cout << "首页、公开课、登录、注册...(公共头部)" << endl;
  }
  void footer()
  {
    cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
  }
  void left()
  {
    cout << "Java,Python,C++...(公共分类列表)" << endl;
  }
  void content()
  {
    cout << "C++学科视频" << endl;
  }
};
void test01()
{
  //Java页面
  cout << "Java下载视频页面如下: " << endl;
  Java ja;
  ja.header();
  ja.footer();
  ja.left();
  ja.content();
  cout << "--------------------" << endl;
  //Python页面
  cout << "Python下载视频页面如下: " << endl;
  Python py;
  py.header();
  py.footer();
  py.left();
  py.content();
  cout << "--------------------" << endl;
  //C++页面
  cout << "C++下载视频页面如下: " << endl;
  CPP cp;
  cp.header();
  cp.footer();
  cp.left();
  cp.content();
}
int main() {
  test01();
  system("pause");
  return 0;
}

如上面代码所示:程序中出现了大量重复的代码。我们现在就需要想办法解决这个问题。

继承实现:

//公共页面
class BasePage
{
public:
  void header()
  {
    cout << "首页、公开课、登录、注册...(公共头部)" << endl;
  }
  void footer()
  {
    cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
  }
  void left()
  {
    cout << "Java,Python,C++...(公共分类列表)" << endl;
  }
};
//Java页面
//继承写法: class 子类名:继承方式 父类名
class Java : public BasePage
{
public:
  void content()
  {
    cout << "JAVA学科视频" << endl;
  }
};
//Python页面
class Python : public BasePage
{
public:
  void content()
  {
    cout << "Python学科视频" << endl;
  }
};
//C++页面
class CPP : public BasePage
{
public:
  void content()
  {
    cout << "C++学科视频" << endl;
  }
};
void test01()
{
  //Java页面
  cout << "Java下载视频页面如下: " << endl;
  Java ja;
  ja.header();
  ja.footer();
  ja.left();
  ja.content();
  cout << "--------------------" << endl;
  //Python页面
  cout << "Python下载视频页面如下: " << endl;
  Python py;
  py.header();
  py.footer();
  py.left();
  py.content();
  cout << "--------------------" << endl;
  //C++页面
  cout << "C++下载视频页面如下: " << endl;
  CPP cp;
  cp.header();
  cp.footer();
  cp.left();
  cp.content();
}
int main() {
  test01();
  system("pause");
  return 0;
}

总结:

继承的好处:可以减少重复的代码


class A : public B;


A 类称为子类 或 派生类

B 类称为父类 或 基类


派生类中的成员,包含两大部分


一类是从基类继承过来的,一类是自己增加的成员。


从基类继承过过来的表现其共性,而新增的成员体现了其个性

继承方式

根据上面的过程我们已经知道了继承的语法:class 子类 : 继承方式 父类

继承方式一共有三种:

  • 公共继承
  • 保护继承
  • 私有继承

父类里面private的内容,子类不管哪种方式继承都拿不到。


如果是公有继承:那么父类除私有外,其他的都是原来的权限不变。


如果是保护继承:除私有外都变为了protected保护权限。


如果是私有继承:除父类私有的以外,其他的都变成了private私有权限。


示例:

class Base1
{
public: 
  int m_A;
protected:
  int m_B;
private:
  int m_C;
};
//公共继承
class Son1 :public Base1
{
public:
  void func()
  {
    m_A; //可访问 public权限
    m_B; //可访问 protected权限
    //m_C; //不可访问父类的私有权限
  }
};
void myClass()
{
  Son1 s1;
  s1.m_A; //其他类只能访问到公共权限
    //s1.m_B;//到子类Son1中,m_B变成了保护权限,类外访问不到。
}
//保护继承
class Base2
{
public:
  int m_A;
protected:
  int m_B;
private:
  int m_C;
};
class Son2:protected Base2
{
public:
  void func()
  {
    m_A; //可访问 protected权限
    m_B; //可访问 protected权限
    //m_C; //不可访问
  }
};
void myClass2()
{
  Son2 s;
  //s.m_A; //不可访问,保护继承,父类的公有属性来到Son2中变为保护权限,类外访问不到
//私有继承
class Base3
{
public:
  int m_A;
protected:
  int m_B;
private:
  int m_C;
};
class Son3:private Base3
{
public:
  void func()
  {
    m_A; //可访问 private权限
    m_B; //可访问 private权限
    //m_C; //不可访问
  }
};
class GrandSon3 :public Son3
{
public:
  void func()
  {
    //Son3是私有继承,所以继承Son3的属性(私有权限)在GrandSon3中都无法访问到
    //m_A;
    //m_B;
    //m_C;
  }
};

回顾一下继承方式不同,子类权限的表示:

首先,对于父类而言,父类中隐私的东西,子类不管什么方式继承都无法访问;

如果是公共继承,父类中的公有和保护属性的访问权限没有变化,如果是保护继承,公有和保护权限变成了保护,如果是私有继承,这两个权限就都变成了私有。

继承中的对象模型

问题:从父类继承过来的成员,哪些属于子类对象中?

class Base
{
public:
  int m_A;
protected:
  int m_B;
private:
  int m_C; //私有成员只是被隐藏了,但是还是会继承下去
};
//公共继承
class Son :public Base
{
public:
  int m_D;
};
void test01()
{
    //16
    //父类中所有非静态成员属性都会被子类继承下去
    //父类中私有成员属性 是被编译器给隐藏了,因此是访问不到的,但是确实是被继承了
  cout << "sizeof Son = " << sizeof(Son) << endl;
}
int main() {
  test01();
  system("pause");
  return 0;
}

通过工具验证:

打开开发人员命令提示符工具。


如何找到文件位置,复制,然后在工具里面跳转到项目文件所在盘,“cd 文件路径”,跳转之后再输入dir,定位到当前CPP文件的盘符


然后输入: cl /d1 reportSingleClassLayout查看的类名 所属文件名


上面一串英文的意思就是报告单个类的布局。

结论:

       父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到

继承中构造和析构顺序

子类继承父类后,当创建子类对象,也会调用父类的构造函数

问题:

父类和子类的构造和析构顺序是谁先谁后?

class Base 
{
public:
  Base()
  {
    cout << "Base构造函数!" << endl;
  }
  ~Base()
  {
    cout << "Base析构函数!" << endl;
  }
};
class Son : public Base
{
public:
  Son()
  {
    cout << "Son构造函数!" << endl;
  }
  ~Son()
  {
    cout << "Son析构函数!" << endl;
  }
};
void test01()
{
  //继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
  Son s;
}
int main() {
  test01();
  system("pause");
  return 0;
}

说明是先构造父类,再子类,析构相反


总结:

       继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反  


相关文章
|
10天前
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
42 16
|
7天前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
25 5
|
2月前
|
编译器 C++ 开发者
【C++】继承
C++中的继承是面向对象编程的核心特性之一,允许派生类继承基类的属性和方法,实现代码复用和类的层次结构。继承有三种类型:公有、私有和受保护继承,每种类型决定了派生类如何访问基类成员。此外,继承还涉及构造函数、析构函数、拷贝构造函数和赋值运算符的调用规则,以及解决多继承带来的二义性和数据冗余问题的虚拟继承。在设计类时,应谨慎选择继承和组合,以降低耦合度并提高代码的可维护性。
39 1
【C++】继承
|
3月前
|
IDE Java 程序员
C++ 程序员的 Java 指南
一个 C++ 程序员自己总结的 Java 学习中应该注意的点。
30 5
|
3月前
|
安全 编译器 程序员
C++的忠实粉丝-继承的热情(1)
C++的忠实粉丝-继承的热情(1)
25 0
|
7天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
43 18
|
7天前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
32 13
|
7天前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
20 5
|
7天前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
23 4
|
7天前
|
设计模式 IDE 编译器
【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
本项目旨在通过C++编程实现一个教学游戏,帮助小朋友认识动物。程序设计了一个动物园场景,包含Dog、Bird和Frog三种动物。每个动物都有move和shout行为,用于展示其特征。游戏随机挑选10个动物,前5个供学习,后5个用于测试。使用虚函数和多态实现不同动物的行为,确保代码灵活扩展。此外,通过typeid获取对象类型,并利用strstr辅助判断类型。相关头文件如&lt;string&gt;、&lt;cstdlib&gt;等确保程序正常运行。最终,根据小朋友的回答计算得分,提供互动学习体验。 - **任务描述**:编写教学游戏,随机挑选10个动物进行展示与测试。 - **类设计**:基类
23 3

热门文章

最新文章