C++(学习)2024.9.25

news2024/11/16 15:41:59

目录

继承

概念

构造函数

1.派生类与基类构造函数的关系

2.解决方案

(1)补充基类的无参构造函数

(2)手动在派生类中调用基类构造函数

1.透传构造

2.委托构造

3.继承构造

3.对象的创建与销毁流程

4.多重继承

(1)概念

(2)可能出现的问题

1.重名问题

2.菱形继承

权限

1.权限修饰符

2.不同权限的继承

(1)公有继承

(2)保护继承

(3)私有继承


继承

概念

继承就是面向对象的三大特性之一,体现了代码复用的思想。
继承就是在一个已存在的类的基础上,建立一个新的类,并拥有其特性。
1.已存在的类被称为“基类”或者“父类”
2.新建立的类被称为“派生类”或者“子类”

#include <iostream>
using namespace std;

// 基类
class Father
{
private:
    string name = "张";
public:
    void set_name(string name)
    {
        this->name = name;
    }
    string get_name()
    {
        return name;
    }
    void work()
    {
        cout << "我的工作是厨师,我负责炒菜" << endl;
    }
};

// 派生类
class Son:public Father
{
};

int main()
{
    Son son;
    cout << son.get_name() << endl;
    son.work();
    return 0;
}

上面的代码,Son类的功能几乎与Father类重叠,在实际的使用过程中,派生类会做出一些与基类的差异化。
●修改继承来的基类内容
属性:

1、公有属性可以直接更改。更改后基类中的属性也会改变,因为改的是同一份变量        

2、私有属性,需要使用基类公有函数进行更改。
行为:函数隐藏,通过派生类实现一个同名同参数的函数,来隐藏基类的函数。
●新增派生类的内容

#include <iostream>
using namespace std;

// 基类
class Father
{
private:
    string name = "张";
public:
    void set_name(string name)
    {
        this->name = name;
    }
    string get_name()
    {
        return name;
    }
    void work()
    {
        cout << "我的工作是厨师,我负责炒菜" << endl;
    }
};

// 派生类
class Son:public Father
{
public:
    void init()
    {
        set_name("王");
    }

    void work()
    {
        cout << "我的工作是司机" << endl;
    }

    void game()
    {
        cout << "开挖掘机" << endl;
    }
};


int main()
{
    Son son;
    son.init();

    cout << son.get_name() << endl;
    son.work(); 
    son.game();

    son.Father::work();
    return 0;
}

        基类和派生类都是相对的,一个类可能存在又是基类又是派生类的情况,取决于那两个类进行比较。

构造函数

1.派生类与基类构造函数的关系

构造函数与析构函数不能被继承。

#include <iostream>
using namespace std;

// 基类
class Father
{
private:
    string name;
public:
    Father(string name):name(name){}    // 有参构造函数
    string get_name()
    {
        return name;
    }
};

// 派生类
class Son:public Father
{
};

int main()
{
//    Son s;    // 找不到基类的无参构造函数
//    Son s("张"); // 找不派生类的有参构造函数
    return 0;
}

2.解决方案

(1)补充基类的无参构造函数
#include <iostream>
using namespace std;

// 基类
class Father
{
private:
    string name;
public:
    // 无参构造函数
    Father():name("张"){}

    // 有参构造函数
    Father(string name):name(name){}

    string get_name()
    {
        return name;
    }
};

// 派生类
class Son:public Father
{
public:
};

int main()
{
    Son s;    
    cout << s.get_name() << endl;
    return 0;
}
(2)手动在派生类中调用基类构造函数
1.透传构造

在派生类的构造函数中,调用基类的构造函数,实际上编译器自动添加的派生类构造函数,调用基类无参构造函数时,就是采用的这种方式。

#include <iostream>
using namespace std;

// 基类
class Father
{
private:
    string name;
public:
    // 有参构造函数
    Father(string name):name(name){}
    string get_name()
    {
        return name;
    }
};

// 派生类
class Son:public Father
{
public:
    // 编译器会自动添加构造函数,透传调用基类无参构造函数(透传构造)
    // Son():Father(){}
    // 手动添加构造函数,透传构造
    Son():Father("王"){}
    // 有参构造函数,调用基类有参构造函数
    Son(string fn):Father(fn){}
};

int main()
{
    Son s;
    cout << s.get_name() << endl;
    Son s1("张");
    cout << s1.get_name() << endl;
    return 0;
}
2.委托构造

一个类的构造函数可以调用这个类的另一个构造函数,但是需要避免循环委托。

        委托构造的性能低于透传构造,但是代码的“维护性更好”,因为通常一个类中构造函数都会委托给能力最强(参数最多)的构造函数。代码重构时,只需要更改这个能力最强的构造函数即可。

#include <iostream>
using namespace std;

// 基类
class Father
{
private:
    string name;
public:
    Father(string name):name(name){}    // 有参构造函数
    string get_name()
    {
        return name;
    }
};

// 派生类
class Son:public Father
{
public:
    Son():Son("李"){}    // 委托构造
    Son(string fn):Father(fn){}    // 有参构造函数,调用基类有参构造函数
};

int main()
{
    Son s;
    cout << s.get_name() << endl;

    Son s1("赵");
    cout << s1.get_name() << endl;

    return 0;
}
3.继承构造

C++11新增的写法,只需要一句话,就可以自动给派生类添加n(n个为基类构造函数的个数)个构造函数。并且每个派生类的构造函数格式都与基类相同,每个派生类的构造函数都通过透传构造调用对应格式的基类构造函数。

#include <iostream>
using namespace std;

// 基类
class Father
{
private:
    string name;
public:
    Father():Father("张"){}
    Father(string name):name(name){}    // 有参构造函数
    string get_name()
    {
        return name;
    }
};

// 派生类
class Son:public Father
{
public:
    
    using Father::Father;
    // 只需要补充这一句话,编译器就会自动添加下面两种构造函数    
    // Son():Father(){}
    // Son(string fn):Father(fn){}
};

int main()
{
    Son s;
    cout << s.get_name() << endl;
    Son s1("王");
    cout << s1.get_name() << endl;
    return 0;
}

3.对象的创建与销毁流程

在继承中,构造函数与析构函数是有一定调用顺序的。

#include <iostream>
using namespace std;

class Value
{
private:
    string str;
public:
    Value(string str):str(str)
    {
        cout << str<< " 调用Value构造函数" << endl;
    }
    
    ~Value()
    {
        cout << str << " 调用Value析构函数" << endl;
    }
};

class Father
{
public:
    static Value s_value;
    Value val = Value("Father 成员变量");
    Father()
    {
        cout << "Father 构造函数被调用了" << endl;
    }

    ~Father()
    {
        cout << "Father 析构函数被调用了" << endl;
    }
};
Value Father::s_value = Value("静态FatherValue");

class Son:public Father
{
public:
    static Value s_value;
    Value val = Value("Son成员变量");
    Son()
    {
        cout << "Son 构造函数被调用了" << endl;
    }

    ~Son()
    {
        cout << "Son 析构函数被调用了" << endl;
    }
};
Value Son::s_value = Value("静态SonValue");

int main()
{
    cout << "主函数被调用了" << endl;

    // 局部代码块
    {
        Son s;
        cout << "对象执行中" << endl;
    }

    cout << "主函数结束了" << endl;
    return 0;
}

上面的执行结果中,可以得到以下的规律:
(1)静态的创建早于非静态。
(2)在创建的过程中,同类型的内存空间基类先开辟,派生类先销毁。创建对象时:先基后派。销毁对象时:先派后基
(3)以“对象执行中为轴”上下对称

4.多重继承

(1)概念

        C++支持多重继承,即一个派生类可以有多个基类,派生类对于每个基类的关系仍然可以看作是一个单继承。

#include <iostream>
using namespace std;

class Sofa
{
public:
    void sit()
    {
        cout << "可以坐着" << endl;
    }
};

class Bed
{
public:
    void lay()
    {
        cout << "可以躺着" << endl;
    }
};

// 派生类
class SofaBed:public Sofa,public Bed
{
};

int main()
{
    SofaBed sobe;
    sobe.lay();
    sobe.sit();
    return 0;
}
(2)可能出现的问题
1.重名问题

当多个基类具有重名成员时,编译器在编译的时候会出现二义性问题。
解决方法:使用类名::方式调用

#include <iostream>
using namespace std;

class Sofa
{
public:
    void sit()
    {
        cout << "可以坐着" << endl;
        }
    void clean()
    {
        cout << "打扫沙发" << endl;
        }
};
class Bed
{
public:
    void lay()
    {
        cout << "可以躺着" << endl;
        }
    void clean()
    {
        cout << "打扫床" << endl;
        }
};

// 派生类
class SofaBed:public Sofa,public Bed
{
};

int main()
{
    SofaBed sobe;
    sobe.lay();
    sobe.sit();
    sobe.Sofa::clean();
    sobe.Bed::clean();
    return 0;
}
2.菱形继承

        当一个派生类有多个基类,且这些基类又有一个共同的基类,就会出现二义性的问题,这种现象被称为(钻石)菱形继承。

有两种解决方式:
1、和重名问题类似,使用基类的类名::方式调用

2、使用虚继承
当出现虚继承时,Furniture类中就会生成一张虚基类表,这个表不占用任何对象的存储空间,属于Furniture类持有,在程序启动时加载进内存空间,表中记录了Furniture函数的调用地址偏移量。
Bed和Sofa对象中会出现一个隐藏的成员变量指针,指向Furniture类中的虚基类表,占用对象的四个字节。
虚继承时,SofaBed类对象会同时拥有两个虚基类表指针成员,在调用时查表解决二义性。

#include <iostream>
using namespace std;

// 家具厂
class Furniture
{
public:
    void func()
    {
        cout << "家具厂里有家具" << endl;
    }
};

class Sofa:virtual public Furniture
{
};
class Bed:virtual public Furniture
{
};

// 派生类
class SofaBed:public Sofa,public Bed
{
};
int main()
{
    SofaBed sobe;
    sobe.func();
    return 0;
}

权限

1.权限修饰符

类内派生类内全局(类外)
private√ ××
protected√ √ ×
public√ √ √ 
#include <iostream>
using namespace std;

class Test
{
protected:
    string str="保护权限";
public:
    Test()
    {
        cout<<str<<endl;
    }
};

class Base:public Test
{
public:
    Base()
    {
        cout<<str<<endl;
    }

};

int main()
{
    Base b;
    //cout<<b.str<<endl;// 错误 b是保护权限

    return 0;
}

2.不同权限的继承

(1)公有继承

        公有继承是使用最多的一种继承方式,在公有继承中,派生类可以继承基类的成员,但是不可以访问基类的私有成员,基类成员的权限在派生类中权限保持不变。

#include <iostream>
using namespace std;

class Base
{
private:
    string str1 = "私有成员";
protected:
    string str2 = "保护成员";
public:
    string str3 = "公有成员";
};

class Son:public Base
{
public:
    Son()
    {
        //       cout << str1 << endl;      // 错误 str1为私有成员
        cout << str2 << endl;
        cout << str3 << endl;
    }
};

int main()
{
    Son s1;
    return 0;
}

(2)保护继承

        在保护继承中,派生类可以继承基类的成员,不可以访问基类的私有成员,基类的公有成员与保护成员,在派生类的权限都是保护权限。

#include <iostream>
using namespace std;

class Base
{
private:
    string str1 = "私有成员";
protected:
    string str2 = "保护成员";
public:
    string str3 = "公有成员";
};
class Son:protected Base
{
public:
    Son()
    {
        //cout << str1 << endl;     // 错误 str1为私有成员
        cout << str2 << endl;
        cout << str3 << endl;
        }
};

int main()
{
    Son s1;
    //    cout << s1.str3 << endl; // 保护成员调用失败
    return 0;
}

(3)私有继承

        在私有继承中,派生类可以继承基类的成员,但是不可以访问基类的私有成员,基类的公有成员与保护成员在派生类中权限都是私有权限。

#include <iostream>
using namespace std;

class Test
{
private:
    string str1="私有成员";
protected:
    string str2="保护成员";
public:
    string str3="公有成员";
};

class Base:private Test
{
public:
    Base()
    {
        //        cout<<str1<<endl;
        cout<<str2<<endl;
        cout<<str3<<endl;
    }
};
class Demo:public Base
{
public:
    Demo()
    {
        cout << str2 << endl;
        cout << str3 << endl;
    }
};


int main()
{
    Base b;
//    cout<<b.Test::str3<<endl;
    return 0;
}

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

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

相关文章

基于Spring Boot+Vue前后端分离的中医药科普系统设计和实现(协同过滤算法)【原创】

&#x1f388;系统亮点&#xff1a;协同过滤算法&#xff1b; 一.系统开发工具与环境搭建 1.系统设计开发工具 后端使用Java编程语言的Spring boot框架 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk17 前端&#xff1a; 技术&#xff1a;框架Vue.js&am…

利用Langchain开发框架研发智能体Agent的过程,以及相关应用场景

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下本文主要介绍了利用langchain开发智能体agent的过程。文章首先阐述了项目背景&#xff0c;随后通过给出样例代码&#xff0c;详细展示了执行过程。此外&#xff0c;本文还探讨了该智能体agent在实际应用场景中的运用…

【漏洞复现】灵当CRM multipleUpload.php接口处存在文件上传漏洞

》》》产品描述《《《 灵当CRM致力于为企业提供客户管理数字化、销售管理自动化、服务管理智能化、项目管理一体化的个性化CRM行业解决方案,构建全生命周期的数字化管理体系,实现可持续的业绩增长! 》》》漏洞描述《《《 灵当CRM系统接口multipleUpload.php文件上传漏洞&#x…

认知战认知作战:认知战战略如何玩转东方文化

认知战认知作战&#xff1a;认知战战略如何玩转东方文化 认知战认知作战&#xff1a;认知战战略如何玩转东方文化 关键词&#xff1a;认知战, 东方文化, 精髓元素, 美学引领, 生活方式连接, 战略故事, 艺术融合, 文化符号, 哲学思想, 古建筑灵感, 传统图案, 限量魅力, 沉浸式…

【JAVA开源】基于Vue和SpringBoot的学科竞赛管理系统

本文项目编号 T 047 &#xff0c;文末自助获取源码 \color{red}{T047&#xff0c;文末自助获取源码} T047&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

小学生管理系统项目

在当今数字化教育的背景下&#xff0c;小学生管理系统应运而生。本项目采用 JSP Servlet JDBC MySQL 的技术组合&#xff0c;并在开发工具 Idea 和 Eclipse 的辅助下&#xff0c;结合数据库管理工具 Navicat 进行开发。 一、系统入口 用户登录入口&#xff1a;为普通用户提…

树上差分详解

零、前言 关于差分&#xff1a; 差分数组详解&#xff0c;一维二维差分-CSDN博客 关于LCA&#xff1a; LCA算法-倍增算法_lca倍增算法-CSDN博客 LCA算法-Tarjan算法_lca数组-CSDN博客 树链剖分——重链剖分&#xff0c;原理剖析&#xff0c;代码详解-CSDN博客 一、树上差…

Docker全家桶:从0到加载本地项目

安装docker&#xff0c;我们选择的是CentenOS 7。 目录 Docker安装 命令 命令别名 数据卷挂载 Dockerfile 容器网络互联 Docker安装 1. 先删除本机旧的或者残留的docker sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest …

Android13 展锐平台拨号中视频彩铃界面方向未与设备方向一致

背景&#xff1a;拨号中视频彩铃界面方向未与设备方向一致&#xff0c;要求视频彩铃界面方向与设备方向一致&#xff0c;修改视频彩铃显示的地方&#xff1b; 如图所示&#xff1a; 修改&#xff1a; packages/services/Telecomm/src/com/android/server/telecom/VideoProvid…

【GUI设计】基于Matlab的图像特征提取GUI系统(9),matlab实现

博主简介&#xff1a;如需获取设计的完整源代码或者有matlab图像代码项目需求&#xff0c;可联系主页简介提供的方式或者文末的扫码。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于Matlab的图像特征提取GUI系统&#xff08;9&a…

得物App荣获国家级奖项,正品保障引领潮流电商新风尚

近日&#xff0c;在2024年中国国际服务贸易交易会上&#xff0c;得物App凭借其在科技创新保障品质消费领域的突出成果&#xff0c;再次荣获国家级殊荣——“科技创新服务示范案例”。这是继上海市质量金奖之后&#xff0c;得物App获得的又一个“高含金量”奖项。 作为深受年轻人…

YOLOv8改进 - 注意力篇 - 引入(A2-Nets)Double Attention Networks注意力机制

一、本文介绍 作为入门性篇章&#xff0c;这里介绍了A2-Nets网络注意力在YOLOv8中的使用。包含A2-Nets原理分析&#xff0c;A2-Nets的代码、A2-Nets的使用方法、以及添加以后的yaml文件及运行记录。 二、A2-Nets原理分析 A2-Nets官方论文地址&#xff1a;A2-Nets文章 A2-Net…

美妆电商与AI知识库:构建智能化购物体验

在当今这个数字化时代&#xff0c;美妆电商行业正经历着前所未有的变革。随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;AI知识库在美妆电商领域的应用日益广泛&#xff0c;不仅重塑了传统的购物模式&#xff0c;还为消费者带来了前所未有的智能化购物体验…

手把手教你找到海外网红合作:海外红人营销渠道

在全球范围内&#xff0c;许多企业寻求与知名网红建立合作关系&#xff0c;以推广产品、共同创作内容或探索其他合作形式。以下是一些有效的方法来实现这一目标&#xff1a; 利用社交媒体平台&#xff1a;社交媒体是寻找海外网红的首选途径。平台如Instagram、YouTube和TikTok拥…

windows10使用bat脚本安装前后端环境之node环境设置

首先需要搞清楚node在本地是怎么安装配置、然后在根据如下步骤编写bat脚本&#xff1a; 思路 1.下载需要安装node版本zip格式包 2.配置环境变量 3.安装插件 可以根据自己需要来定义与配置&#xff08;如下添加redis与node配置&#xff09; bat脚本&#xff1a; echo off…

Node的安装和配置

1、安装Node 下载nodejs 链接&#xff1a;下载 | Node.js 中文网 官网下载最新版本&#xff1a;https://nodejs.org/en/download/ 一路点击Next&#xff0c;最后Finish。nodejs一般会下载在C盘里。 下载完成后&#xff0c;可以在cmd中查看安装的nodejs和npm版本&#xff0c;…

python单例和工厂模式

设计模式 设计模式是一种编程套路&#xff0c;可以极大的方便程序的开发 最常见、最经典的设计模式&#xff0c;就是学习的面向对象 除了面向对象之外&#xff0c;在编程中也有很多既定的套路可以方便开发&#xff0c;我们称之为设计模式&#xff1a; 单例、工厂模式建造者…

2022年上真题(案例分析)

一、数据流图 1. E1&#xff1a;商户 E2&#xff1a;外卖平台 E3&#xff1a;用户 E4&#xff1a;支付系统 2. D1&#xff1a;商户用户信息表 D2&#xff1a;订单表 D3&#xff1a;餐品信息表 D4&#xff1a;评价表 3. 数据流名称 …

Linux设备驱动中的异步通知与异步I/O学习s

1、异步通知的概念和作用 异步通知的意思是&#xff1a;一旦设备就绪&#xff0c;则主动通知应用程序&#xff0c;这样应用程序根本就不需要查询设备状态&#xff0c;这一点非常类似于硬件上”中断“的概念&#xff0c;比较准确的称谓是”信号驱动的异步I/O“。信号是在软件层次…