首页 > 编程语言 >【c++继承篇】--继承之道:在C++的世界中编织血脉与传承

【c++继承篇】--继承之道:在C++的世界中编织血脉与传承

时间:2025-01-17 22:59:09浏览次数:3  
标签:继承 成员 基类 C++ -- 派生类 public 构造函数

目录


引言

今天学习继承,继承(Inheritance)
是面向对象编程中的一种核心概念,它允许一个类(子类)从另一个类(父类)派生,继承父类的属性和方法。

一、定义

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

我们通过一个简单的代码示例来说明下:

class Person
{
public :
	void print()
	{
		cout << " name:" << _name << " id: " << _id << endl;
	}
protected:
	string _name= "per";
	int _id = 134;
};

class Student :public Person
{
protected:
	int _stuid;
};

在上述代码中,Student 类就是继承了父类Person,继承父类的成员(成员函数+成员变量)都会变成子类的一部分。父类person就是基类,子类Student也就是派生类。


二、继承定义格式

2.1定义格式

在这里插入图片


2.2继承关系和访问限定符

继承方式有public 继承protected 继承private 继承。访问限定符有public 访问protected访问
private访问

2.3继承后子类访问权限

类成员/继承方式public 继承
基类public派生类的public成员
基类 protected派生类的protected成员
基类 private派生类中不可见

总:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私
    有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面
    都不能去访问它。
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
    派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
  5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强

三、基类和派生类赋值转换

派生类对象 可以赋值给基类的对象 / 基类的指针 / 基类的引用 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。
相反 基类成员无法赋值给派生类成员。
如:

class Person
{
protected :
    string _name; // 姓名
    string _sex;  // 性别
    int _age; // 年龄
};
class Student : public Person
{
public :
  int _No; // 学号
};
void Test ()
{
   Student s ;
 // 1.子类对象可以赋值给父类对象/指针/引用
   Person p = s ;
   Person* p1 = &s;
   Person& p2 = s;
    
    //2.基类对象不能赋值给派生类对象
    // 3.基类的指针可以通过强制类型转换赋值给派生类的指针
    p1 = &s;
    Student* s1 = (Student*)pp; // 这种情况转换时可以的。
    s1->_No = 10;
}

四、继承的作用域

继承的作用域决定了从基类继承到派生类的成员(包括变量和方法)的访问权限。
在c++继承体系中基类和派生类都有独立的作用域。当子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)


4.1同名变量

在下面代码中,基类和派生类都有一个_num这个变量。

class Person
{
protected:
	string name = "xiaolizi";
	int _num = 111;

};
y隐藏/重定义  子类和父类有同名成员
class Student :public Person
{
public:
	void print()
	{
		cout << "名字:" << name << endl;
	
		cout << _num << endl;
	}
protected:
	int _num = 333;
};
int main()
{
	Student s;
	s.print();
}

输出结果:
在这里插入图片描述
若果想要打印基类的_num则只需要在print函数里面加入::限定符:

void print()
	{
		cout << "名字:" << name << endl;
		cout <<person:: _num << endl;
	}

4.2同名函数

如果基类和派生类都出现名字相同的函数,会发现什么?
如下:

class A
{
public:
  void fun()
  {
    cout << "func()" << endl;
  }
};
class B : public A
{
public:
  void fun(int i)
  {
    A::fun();
    cout << "func(int i)->" <<i<<endl;
  }
};
void Test()
{
	B b;
	b.fun(2);
}

输出结果:
在这里插入图片描述

B中的fun和A中的fun不是构成重载,因为不是在同一作用域
B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。

要访问A中的func函数,需要加 :: 限定符


五、派生类的默认成员构造函数

在类中有六个默认成员函数(分别是:默认构造函数、拷贝构造函数、拷贝赋值运算符、析构函数、移动构造函数、移动赋值运算符),一起看看:
在这里插入图片描述


5.1构造函数调用顺序:

  • 创建派生类对象时,从最顶层的基类开始,逐层向下调用构造函数,直到派生类。

  • 接着,按照派生类中成员变量的声明顺序初始化成员变量(若成员是对象,则调用其构造函数)。

  • 最后,执行派生类构造函数体中的代码。

5.2析构函数调用顺序:

  • 销毁派生类对象时,首先调用派生类的析构函数。

  • 然后,按照成员变量声明的逆序调用成员变量的析构函数(若成员是对象)。

  • 最后,从最顶层的基类开始,逐层向上调用析构函数,直到派生类的基类

代码演示:

#include <iostream>
using namespace std;

class Base {
public:
    Base() { cout << "Base constructor\n"; }
    ~Base() { cout << "Base destructor\n"; }
};

class Derived : public Base {
public:
    Derived() { cout << "Derived constructor\n"; }
    ~Derived() { cout << "Derived destructor\n"; }
};

int main() {
    Derived d;
    return 0;
}

运行结果:

Base constructor
Derived constructor
Derived destructor
Base destructor

在上述代码中,
当对象 d 被创建时,首先调用 Base 类的构造函数,然后调用 Derived 类的构造函数。
当对象销毁时,首先调用 Derived 类的析构函数,最后调用 Base 类的析构函数。


构造调用总结:

  • 基类构造函数首先调用。
  • 成员对象构造函数按成员声明的顺序调用。
  • 派生类构造函数最后调用

析构调用总结:

  • 成员对象析构顺序:按照它们在类定义中的声明顺序销毁。
  • 继承关系:析构函数的调用顺序是先派生类,后基类。

5.3调用关系

  • 派生类的构造函数必须调用基类的构造函数来初始化基类的成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表中显式调用基类的一个构造函数。
  • 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化
  • 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才保证派生类对象先清理派生类成员再清理基类成员的顺序。

示意图如下:
在这里插入图片描述

标签:继承,成员,基类,C++,--,派生类,public,构造函数
From: https://blog.csdn.net/2401_83157962/article/details/145075357

相关文章

  • 财务管理系统【附源码】
    项目简介前面所做的功能分析,只是本系统的一个大概功能,这部分需要在此基础上进行各个模块的详细设计。设计的管理员的详细功能见下图,管理员登录进入本人后台之后,管理职工和部门,管理企业资产,经营信息和职工薪资。设计的职工的详细功能见下图,职工查询和查看企业经营和企业资......
  • 选课管理【附源码】
    项目简介基于JSP技术的选课管理系统旨在提高学校管理人员的工作效率,通过信息化手段优化学生选课流程。该系统采用B/S架构,利用Java语言进行编码,MySQL数据库进行数据存储,以及Tomcat服务器处理请求和响应消息。系统主要功能包括:用户管理:系统允许管理员对用户信息进行管理,包括学......
  • SSM旅游信息管理系统
    ......
  • js逆向笔记 绕过某网站开发者工具检测
    js逆向笔记绕过某网站开发者工具检测在这篇博客中,我将分享我在逆向分析爱企查时的一些发现与绕过技巧。最开始,我是偶然发现了这个网站,它在正常使用浏览器按下F12打开开发者工具时,似乎有某种方式禁用了开发者工具。不过,我没有放弃,继续从浏览器的右上角点击手动打开开发者......
  • C语言数据类型和变量(中)
    变量1.变量的创建上一篇我们所讲的是数据类型,而类型用来干什么的-创建变量的,在C语⾔中,我们把经常变化的值称为变量,不变的值称为常量,如intage;便是整型变量。变量在创建的时候就给⼀个初始值,就叫初始化。如charc='w';2.变量的分类全局变量:在⼤括号外部定义的变量就是全......
  • 【搜索】洛谷P1123 取数游戏
    P1123取数游戏搜索顺序:按格子枚举。思想类比AcWing843.n-皇后问题按格子枚举方法,以及AcWing1116.马走日AcWing1117.单词接龙AcWing1118.分成互质组,体会恢复现场写在for循环内部与写在for循环外部的区别。最大的区别:恢复现场写在for循环外可以不用清空标记数组。......
  • 锐捷路由器网关RG-NBR6135-E和锐捷交换机 Ruijie Reyee RG-ES224GC 电脑登录web方法
    2025年1月17日22:29:35最近淘了点东西,准备在家里搞一套深度学习的服务器,先把网关和交换机搞到了锐捷路由器网关RG-NBR6135-E电脑登录web方法在拿到机器的时候,如果不是全新建议拿根牙签,差入reset5-10秒,灯光会全部闪几下,重置机器,因为有些机器会配置的ip和网段无法访问默认的w......
  • 网站SEO优化
    今天的主要任务是探究wordpress中各种插件1.网站的动态效果展示:(1)metaslider:可以在首页或者其他地方加幻灯片的轮播效果,显得页面更加丰满(2)SmartSlider:类似幻灯片的形式,下面展示和商品相关的视频,可以手动点击播放我本来想找的插件是使所有的商品图片从右向左自动滑入滑出,但是基......
  • 【Windows攻防】恶意软件容器化
    #windows微软在2022年7月为了帮助用户保持安全,在Office中默认阻止了internet宏。阻止从Internet下载的文档中的VBA宏。接下来我们来了解一下MOTW标记,其实就是网络标记。什么是MOTW标记?MOTW全名MarkoftheWeb,他是windows操作系统中的一个安全特性,为了帮助用户在处理下载文......
  • 【工具】Gitea 的安装
    安装#root下进行#新建用户sudoadduser\--system\--shell/bin/bash\--gecos'GitVersionControl'\--group\--disabled-password\--home/home/git\git#创建所需的目录结构。sudomkdir-p/etc/gitea/var/lib/gitea/{custom,......