【C++】面向对象三大特性之继承

news/2025/2/23 1:06:04/

【C++】面向对象三大特性之继承

  • 继承的概念
  • 继承基类成员访问方式的变化
  • 子类到父类对象之间赋值兼容转换
  • 继承中的作用域
  • 子类的默认成员函数
  • 继承和友元、静态成员的关系
  • 菱形继承和菱形的虚拟继承
    • 虚拟继承解决二义性和数据冗余

继承的概念

继承:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类 。而以前我们接触的复用都是函数复用,继承是类设计层次的复用

继承基类成员访问方式的变化

在这里插入图片描述
继承后的成员权限:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的
  2. 基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected> private。
class A {
public:int a = 10;
protected:int b = 20;
private:int c = 30;
};class B :private A {void print(){cout << a << endl;cout << b << endl;//cout << c << endl;不可访问}
};

子类到父类对象之间赋值兼容转换

  • 派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割
  • 基类对象不能赋值给派生类对象
  • 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的
  • 切片仅限公有继承。如:父类为公有,子类保护或私有继承后,成员变为保护和私有,子类再切片给父类,那么被继承的成员权限与父类不一样了,所以切片仅限公有继承
class A
{
public:int _a;
};class B : private A
{
public:int _b;
};
class C : public A
{
public:int _c;
};int main()
{B b;C c;A a(b);//出错A aa(c);
}

继承中的作用域

  1. 在继承中父类和子类都有自己独立的类域。
  2. 当子类和父类中存在同名成员时,子类将会屏蔽继承于父类的同名成员,这种情况被称为隐藏或重定义。(子类内部优先使用自己类域的同名成员,子类中使用 基类::基类成员 显示访问)
  3. 子类和父类中的同名成员函数并不构成函数重载,因为它们所处于不同的类域,子类会隐藏父类同名函数。
  4. 父类和子类尽量不要使用同名成员。

子类的默认成员函数

父、子类中成员处理方式

  • 子类中有两部分成员,一类是子类原生的成员,另一类是继承于父类的成员。
  • 对于原生成员,按照普通类调用默认成员函数的规则进行处理;对于继承自父类的成员,将会调用父类中的默认成员函数进行处理。(各玩各的)

需要自己写默认成员函数的情况

  • 对于默认构造函数,如果父类没有默认构造函数,就需要我们自己去写,显式调用构造

  • 对于拷贝构造和赋值重载,如果子类存在深拷贝的问题,这个时候就需要我们自己实现拷贝构造和赋值重载来实现深拷贝

  • 对于析构函数,根据具体实际的情况,如果子类有资源需要释放,那我们就需要自己手动实现析构。

以下是显示写默认成员函数的例子
构造:父类中没有默认构造函数,需要在子类中显示调用
拷贝构造函数:必须调用基类的拷贝构造完成基类的拷贝初始化
派生类的赋值重载必须要调用基类的赋值重载完成基类的复制

class Person
{
public:Person(const char* name): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;delete[] p;}
protected:string _name; // 姓名int* p = new int[10];
};
 派生类中
 1、构造函数,父类成员初始化必须调用父类的构造函数
class Student : public Person
{
public:Student(const char* name, int num):Person(name)//调用父类的构造函数,_num(num), _address("南京"){}Student(const Student& s):Person(s)//发生切片 子类对象赋值给父类对象, _num(s._num), _address(s._address){}Student& operator=(const Student& s){if (this != &s){Person::operator=(s);//切片_num = s._num;}return *this;}//析构函数//子析构函数和父析构函数构成隐藏关系(由于多态关系需求,所有析构函数都会处理成destructor函数名)//调用析构函数的时候,先析构子类,在析构父类;子类不需要显示调用父类析构,子类析构后会自动调用父类析构~Student(){cout << "~Student()" << endl;}protected:int _num; //学号string _address;
};

我们并不需要显式调用父类的析构函数,因为出了子类析构函数的作用域,编译器会自动调用父类的析构。手动调用父类析构将会造成重复析构。

继承和友元、静态成员的关系

  1. 友元关系不能被继承
  2. 父类中的静态成员也会被继承,但是整个继承关系中共用这个静态成员

菱形继承和菱形的虚拟继承

  1. 什么是菱形继承?菱形继承的问题是什么?
    菱形继承是多继承的一种特殊情况,父类对象二义性,数据冗余
    在这里插入图片描述
class A
{
public:int _a;
};class B : public A
//class B : virtual public A
{
public:int _b;
};
class C : public A
//class C : virtual public A
{
public:int _c;
};class D : public B, public C
{
public:int _d;
};
int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}

在这里插入图片描述
从上图可以看出,D中会有两份A成员,调用时存在二义性和数据冗余

虚拟继承解决二义性和数据冗余

未使用虚拟继承
在这里插入图片描述
通过调用内存,会发现对象d中存在两份的_a,存在二义性和数据冗余

在上述代码中,class B : virtual public A;class C : virtual public A
在这里插入图片描述
当使用了虚拟继承,通过调用内存,发现对象d中仅有一份_a,但是继承于B类和C类的_b和_c上方多了一串地址,查找这个地址,发现这个地址之后的位置存放一个数字0x14(十进制20),这个数字就是b中_a距离公共_a的偏移量,如【0x0115FE5C+0x00000014=0x0115FE70】这样就解决了菱形继承成员冗余的问题

这里的A类叫做虚基类,在对象d中,将虚基类的成员放到一个公共的位置,继承的B、C类需要找到A的成员,通过虚基表【存储偏移量的表】中的偏移量进行计算。可以看到虚基表中第一行还空置了4个字节,这块空间存放的也是一个偏移量,它是指向虚基表的指针或者偏移量表格指针


http://www.ppmy.cn/news/966229.html

相关文章

峰瑞报告:3D打印40年,从小众技术到大众应用还有多远?

注&#xff1a;本文内容由峰瑞资本委托发布&#xff0c;作者&#xff1a;颜黔杭。 十余年前&#xff0c;3D打印风头正盛。2012年&#xff0c;美国《时代周刊》将3D打印产业列为“美国10大增长最快的工业”。同一年&#xff0c;中国3D打印技术产业联盟正式成立&#xff0c;多地建…

AI-LLM人物访谈:Noam Shazeer 是 Google 的前 200 号员工,Character.AI:AI Agents 平台下的大模型“民主化”梦想

Character.AI&#xff1a;AI Agents 平台下的大模型“民主化”梦想 海外独角兽|海外独角兽官方账号2023-05-06 20:04:17 Character.AI 是 AGI 时代备受瞩目的公司之一&#xff0c;海外独角兽曾对其有过深度分析&#xff1a;作为聊天机器人&#xff0c;它有着比 ChatGPT 更丰富…

2022年10大最重要的科技事件和突破!

2022年最重要的10大科技事件和突破&#xff1a; 1. AI生成 文本到图像&#xff08;DALL-E2&#xff09;和文本到视频&#xff08;合成&#xff09;工具成为主流。 语言模型&#xff08;如ChatGPT和Cicero&#xff09;的推出&#xff0c;已经被用于编写/调试代码、创建营销计划…

OpenAI 和 Google 会输给谁?

微软创始人、前 CEO 史蒂夫鲍尔默曾说过&#xff1a;「Linux 是一种癌症」。 「但它带来了很好的竞争&#xff0c;它迫使我们创新&#xff0c;迫使我们证明我们提供的价格和价值。」 大模型时代还需要开源吗&#xff1f; 日前&#xff0c;一份来自 Google 内部的文档泄露在网络…

揭晓3类AI无法取代的工作,高学历竟没有优势!

整理 | 朱珂欣 出品 | CSDN程序人生&#xff08;ID&#xff1a;coder_life&#xff09; 上周&#xff0c;IBM 就打响“AI 取代潮”的第一枪&#xff0c;CEO Arvind Krishna 在接受彭博社采访时表示&#xff0c;将暂停招聘其认为未来几年可能会被人工智能取代的 7800 个职位。…

微软发布自己的Linux发行版,“Linux是种癌症”影响犹在

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源 在内部使用两年并自 2022 年 10 月起以公共预览版运行后&#xff0c;微软终于在日前正式公开发布了其 Azure Linux 的发行版。 …

centos安装最新postgresql数据库(15.3版本),漏洞修复

注意: 如果是升级版本要把之前的数据备份, 备份的命令我放到最后了,用dump格式的文件小一些. 一、下载资源包 1 下载地址 RepoView: PostgreSQL PGDG 15 Updates RPMs​ 下载4个包 如果选择其他版本: ​ 从这里进去选择合适的版本 ​ 选择适合的版本 ​ 点击进入下载

数据库课程设计(实训)

1..数据库设计 &#xff08;1&#xff09;项目背景 已知产品供应与订购的业务关系如下图&#xff1a; 其中&#xff0c;客户&#xff08;client&#xff09;的属性有&#xff1a;客户编码&#xff08;cno&#xff09;、客户名称&#xff08;cname&#xff09;、所属行业&am…