C++面向对象的第二大特性:继承

news2024/11/24 13:22:44

1.继承的介绍

首先容我先向大家举一个列子:

我这里定义了一个Person的类

class Person
{
protected:
    string name;
    int age;
    string address;

};

在这个基础上,我要定义一个关于Student  ,  Worker 的类

由于Student Worker都具有Person类中的成员变量 , 为了实现类的复用,由此引出继承

继承的概念:

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

上一段代码帮助大家理解:

class Person
{
protected:
    string name;
    int age;
    string address;

};
// 学生这个类继承Person这个类中的成员变量与成员函数
class Student : public Person
{
protected:
    string stuid;
};

 继承的格式:

class 派生类的名字 : 继承方式 基类的名字

继承后的子类成员访问权限:

 注意事项1:父类的private成员在派生类中无论以什么方式继承都是不可见的

这里的不可见指的是派生类对象不管在类里面还是类外面都是不可访问的

用一段代码帮助大家理解

#include<iostream>
#include<string>
using namespace std;
class Person
{
protected:
    string name;
    int age;
private:
    string address;

};
class Student : public Person
{
    void print()
    {
        cout << name << age << address << stuid << endl;// 不能使用address
    }
protected:
    string stuid;
};
int main()
{
    Student s;
    s.address = "faf";不能通过s去访问address
}

2.基类的私有成员在子类都是不可见的,基类的其它成员在子类的访问方式  = min(成员在基类的访问限定符,继承方式), public > protected > private

#include<iostream>
#include<string>
using namespace std;
class A
{
public:
    string name;
protected:
    int age;
private:
    string address;
};
class B : public A
{
    // A中的name在B中的访问是public-> 类里面可以访问 , 类外面也可以访问
    // A中的age在B中的访问是protected -> 类里面可以访问 ,类外面不可以访问
public:
    void print()
    {
        cout << age << " " << name << " " << endl;
    }
};
int main()
{
    B s;
    s.name = "fdadfa";
    // s.age = 18; // 这个方式是错的
    return 0;
}

3. struct 默然的继承方式和访问限定符都是公有的

    class  默然的继承方式和访问限定符都是私有的

2.切割(切片)

前提:用public继承

原则:子类可以赋值给父类,父类不可以给子类

#include<iostream>
#include<string>
using namespace std;
class A
{
public:
    string name;
protected:
    int age;
private:
    string address;
};
class B : public A
{
    
public:
    void print()
    {
        cout << age << " " << name << " " << endl;
    }
};
int main()
{
    B s;
    A t = s;// 子类可以给父类
 //   B c = t; 父类不可以给子类
    return 0;
}

注意:切割要满足赋值兼容 (不会产生临时变量)

#include<iostream>
using namespace std;
class Person
{
public:
    string name = "fafafa";
    int age = 19;
    string address = "dfdadfadaf";

};
class Student : public Person
{
public:
    void print()
    {
        cout << name << " " << age << " " << address << " " << stuid << endl;
    }
protected:
    string stuid = "121231";
};
int main()
{
    Student t;
    Person& tmp = t;
    tmp.age = 29;
    tmp.name = "aaaaaaaaaa";
    t.print();
}

    

tmp是子类中对父类内容的引用,因此对tmp的改变可以影响子类中的内容

3.继承中的作用域

1.在继承体系中基类和派生类都有独立的作用域

2.子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏(重定义)

3.只需要函数名相同就构成隐蔽

#include<iostream>
using namespace std;
class A
{
public:
    void print()
    {
        cout << num << endl;
    }
    int num = 1;
};
class B : public A
{
public:
    int num = 0;
    void print()
    {
        cout << num << endl;

    }
};
int main()
{
    B s;
    s.print();
    return 0;

}

4.子类的默认成员构造函数

        1.构造函数

子类的成员变量可以分为 内置类型 , 自定义类型 , 父类成员变量

原则处理:内置类型不做处理 , 自定义类型调用它的构造函数 , 父类成员变量调用父类的构造函数

#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
    Person(string _name, int _age, string _address)
        :name(_name), age(_age), address(_address)
    {}

protected:
    string name;
    int age;
    string address;

};
class Student : public Person
{
public:
    Student(string _name, int _age, string _address, string _stuid)
        : Person(_name, _age, _address), stuid(_stuid)
    {}

    void print()
    {
        cout << name << age << address << stuid << endl;
    }
protected:
    string stuid;
};
int main()
{
    Student s("fdadfad", 11, "fadfafadfafd", "111111111111");
    return 0;
}

 2.拷贝构造函数

原则处理:内置类型浅拷贝 , 自定义类型调用它的拷贝构造函数 , 父类成员变量调用父类的拷贝构造函数


#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
    Person(string _name, int _age, string _address)
        :name(_name), age(_age), address(_address)
    {}
    Person(const Person& s)
        : name(s.name), age(s.age), address(s.address)
    {}
    Person& operator=(const Person& s)
    {
        name = s.name;
        age = s.age;
        address = s.address;
        return *this;
    }
protected:
    string name;
    int age;
    string address;

};
class Student : public Person
{
public:
    Student(string _name, int _age, string _address, string _stuid)
        : Person(_name, _age, _address), stuid(_stuid)
    {}
    Student(const Student& s)
        : Person(s), stuid(s.stuid) {}
    Student& operator=(const Student& s)
    {
        Person::operator=(s);
        stuid = s.stuid;
    }
    void print()
    {
        cout << name << age << address << stuid << endl;
    }
protected:
    string stuid;
};
int main()
{
    Student s("fdadfad", 11, "fadfafadfafd", "111111111111");
    return 0;
}

3.复制重载

 原则处理:内置类型浅拷贝 , 自定义类型调用它的复制重载函数 , 父类成员变量调用父类的复制重载函数

4.析构函数

注意:析构函数名在编译时会被统一命名成destructor

先析构子 , 再析构父

父类的析构函数会自动调用的

#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
    Person(string _name, int _age, string _address)
        :name(_name), age(_age), address(_address)
    {}
    Person(const Person& s)
        : name(s.name), age(s.age), address(s.address)
    {}
    Person& operator=(const Person& s)
    {
        name = s.name;
        age = s.age;
        address = s.address;
        return *this;
    }
    ~Person()
    {
        cout << "~Person" << endl;
    }
protected:
    string name;
    int age;
    string address;

};
class Student : public Person
{
public:
    Student(string _name, int _age, string _address, string _stuid)
        : Person(_name, _age, _address), stuid(_stuid)
    {}
    Student(const Student& s)
        : Person(s), stuid(s.stuid) {}
    Student& operator=(const Student& s)
    {
        Person::operator=(s);
        stuid = s.stuid;
    }
    ~Student()
    {
        cout << "~Student" << endl;
        Person::~Person();
    }
    void print()
    {
        cout << name << age << address << stuid << endl;
    }
protected:
    string stuid;
};
int main()
{
    Student s("fdadfad", 11, "fadfafadfafd", "111111111111");
    return 0;
}

这段代码的结果是: 

原因是:即使我显示的调用Person的析构函数,在Student析构时,仍会自动调用Person的析构函数

5.多继承

多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。

多继承下派生类的定义格式如下:

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…

{

<派生类类体>

};

其中,<继承方式1>,<继承方式2>,…是三种继承方式:public、private、protected之一。

#include<iostream>
using namespace std;
class A
{
public:
    int _a;
};
class B : public A

{
public:
    int _b;
};
class C :  public A
{
public:
    int _c;
};
class D : public B, public C
{
public:
    int _d;
};

6.菱形继承 

有上图可知B中继承了两份A的成员变量

导致数据冗余和二义性

解决方式:虚拟继承

#include<iostream>
using namespace std;
class A
{
public:
    int _a;
};
class B : virtual public A

{
public:
    int _b;
};
class C : virtual public A
{
public:
    int _c;
};
class D : public B, public C
{
public:
    int _d;
};
int main()
{
    D s;
    s._a = 1;
    s._b = 2;
    s._c = 3;
    s._d = 4;

    return 0;
}

 底层:

这是s的地址

这是s继承B的内容:

继承的第一个是一个指针 575e9c58(小端)这里的地址后会存一个偏移量

在s的原地址上加上一个偏移量就是_a的值了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1690876.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言自定义类型:结构体

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 C语言自定义类型:结构体 收录于专栏【C语言学习】 本专栏旨在分享学习C语言学习的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 结…

EyeMock下载与使用教程

视频眼神修复直视镜头的AI具有极高的灵活性和适应性。它可以根据不同的拍摄环境和主播需求进行个性化设置&#xff0c;确保最佳的视觉呈现效果。在直播互动中&#xff0c;主播可能因为分神或疲劳而失去与观众的直视&#xff0c;这款工具能够迅速识别并修复这一问题&#xff0c;…

苹果M4性能分析:进步神速?还有多少空间?

2024年初&#xff0c;苹果推出了M4处理器&#xff0c;令人意外的是&#xff0c;它的发布距离M3发布仅仅过去了半年时间。更让人惊讶的是&#xff0c;M4首次亮相于iPad Pro。这一新处理器不仅仅是M3的简单升级版本&#xff0c;而是一次全面的架构优化。本文将详细分析M4处理器的…

网络工程师备考1——基础学习

认识设备 1 交换机 一、什么是交换机&#xff1f; 实现不同电脑之间数据的转发 换机是一种用于电(光)信号转发的网络设备。 它可以为接入交换机的任意两个网络节点提供独享的电信号通路。最常见的交换机是以太网交换机。交换机工作于OSI参考模型的第二层&#xff0c;即数据…

sw套合样条曲线

套合样条曲线,可以变成一条曲线,然后可以进行分段

sql select获取mysql所有数据库,指定数据库下的所有表名

介绍一下 MySQL 8.0 中默认安装的几个系统数据库/模式。 当我们安装 MySQL 8.0 并初始化数据库之后&#xff0c;默认会创建以下系统数据库&#xff1a; mysql&#xff0c;存储了 MySQL 服务器正常运行所需的各种信息。 information_schema&#xff0c;提供了访问数据库元数据…

黑马点评1——短信篇(基于session)

&#x1f308;hello&#xff0c;你好鸭&#xff0c;我是Ethan&#xff0c;一名不断学习的码农&#xff0c;很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 &#x1f3c3;人生之义&#xff0c;在于追求&#xff0c;不在成败&#xff0c;勤通…

使用DataGrip连接跳板机后再连接远程服务器的mysql数据库

相比配置本地数据库就是多了一步SSH/SSL配置。 添加新的mysql连接&#xff0c;选择SSH/SSL&#xff0c;勾选Use SSH tunnel&#xff1a; 点击右边的…配置跳板机连接&#xff0c;输入账号密码&#xff0c;然后保存&#xff1a; 接着配置General&#xff0c;里面填上要连接的数…

【蓝桥杯选拔赛真题76】python找出元素 第十四届青少年组蓝桥杯python选拔赛真题 算法思维真题解析

目录 python找出元素 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python找出元素 第十四届蓝桥杯青少年组python比赛选拔赛真题 一、题目要…

谷歌浏览器安装devtools工具

在浏览器中输入极简插件&#xff0c;然后打开如下的网页&#xff0c;在搜素框中输入vue 出现下图 点击推荐下载 &#xff08;地址&#xff1a;https://chrome.zzzmh.cn/info/nhdogjmejiglipccpnnnanhbledajbpd&#xff09; 打开谷歌浏览器如图 选择“扩展程序” 点开之后&…

抖音跳转微信卡片制作教程 小白也能搞

实测可以正常跳转&#xff0c;很牛逼&#xff0c;给大家分享一下~ 这是我做出来抖音发出去的效果&#xff0c;大家会制作了可以去卖钱&#xff0c;市场上一个这个卡片都要卖50-200&#xff0c;很不错的&#xff01;&#xff01; https://pan.baidu.com/s/1xPmGAWPcbAp7eXg7Dc…

防范TOCTOU竞态条件攻击

防范TOCTOU竞态条件攻击 在软件开发过程中&#xff0c;我们常常会遇到需要在使用资源之前检查其状态的情况。然而&#xff0c;如果资源的状态在检查和使用之间发生了变化&#xff0c;那么检查的结果可能会失效&#xff0c;导致软件在资源处于非正常状态时执行无效操作。这种时…

java微服在使用nacos注册中心时,ribbon负载均衡时给部分feign client使用静态serverList

我看很多贴子都是针对eureka环境下&#xff0c;做静态serverList配置&#xff0c;目前国内大部分都用Nacos&#xff0c;所以便研究了一下。 micore-service-x:ribbon:listOfServers: ip1:port,ip2:port2NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBased…

Java基础-反射原理

总结放前面&#xff1a; 反射是可以通过一个类对象或类名称获取到该类的全部信息&#xff08;属性和方法&#xff09;&#xff0c;包括为权限为private。 要使用反射第一步&#xff0c;要获取的类的Class对象&#xff0c;该Class对象存放在堆区&#xff0c;于类加载时创建&…

每日练习之完全背包——兑换零钱,完全背包问题总结

兑换零钱 题目描述 运行代码 #include<bits/stdc.h> #include<iostream> using namespace std; const int mod1e97; int a[20]{1,2,5,10,20,50,100,200,500,1000,2000,5000,10000},dp[100010]; int main() {dp[0]1;for(int i0;i<13;i)for(int ja[i];j<1000…

汇聚荣:新手做拼多多应该注意哪些事项?

新手在拼多多开店&#xff0c;面临的是竞争激烈的市场和复杂的运营规则。要想在这个平台上脱颖而出&#xff0c;必须注意以下几个关键事项。 一、市场调研与定位 深入了解市场需求和竞争对手情况是新手开店的首要步骤。选择有潜力的细分市场&#xff0c;并针对目标消费者群体进…

LaTeX 2022软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; LaTeX 2022是基于ΤΕΧ的一种排版系统&#xff0c;特别适用于生成科技和数学文档的高质量打印。它可用于各种文档类型&#xff0c;从简单信函到完整…

【Flutter】线性布局弹性布局层叠布局

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;Flutter学习 &#x1f320; 首发时间&#xff1a;2024年5月25日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e; 目…

如何修改WordPress网站的域名

我的网站用的是Hostease的虚拟主机&#xff0c;但是域名是之前在其他平台买的&#xff0c;而且已经快到期了&#xff0c;因为主机和域名在不同的平台上&#xff0c;管理不太方便&#xff0c;所以我又在Hostease重新注册了一个域名&#xff0c;然后把网站换成了新的域名&#xf…

【AJAX前端框架】Asynchronous Javascript And Xml

1 传统请求及缺点 传统的请求都有哪些&#xff1f; 直接在浏览器地址栏上输入URL。点击超链接提交form表单使用JS代码发送请求 window.open(url)document.location.href urlwindow.location.href url… 传统请求存在的问题 页面全部刷新导致了用户的体验较差。传统的请求导…