C++(第四天----拷贝函数、类的组合、类的继承)

一、拷贝构造函数(复制构造函数)

1、概念
拷贝构造函数,它只有一个参数,参数类型是本类的引用。如果类的设计者不写拷贝构造函数,编译器就会自动生成拷贝构造函数。大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制,让目标对象的每个成员变量都变得和源对象相等。编译器自动生成的拷贝构造函数称为“默认拷贝构造函数”。
2、格式

class 类名{
public://普通构造函数类名(){            }  //拷贝构造函数  ,参数是本类的引用//如果我们没有自定义,那么编译器就自动生成默认的拷贝构造函数类名(const 类名 &a){            } 
};

3、例子
在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<cstring>using namespace std;class Student{public:Student(const char *name,int age);//普通构造函数~Student();//如果没有定义拷贝构造函数,编译器就自动生成默认拷贝构造函数--浅拷贝---值的拷贝/* Student(Student &a){this->name = a->name;this->age = age;} *///自定义的拷贝构造函数,深拷贝Student(Student &a){cout<<"Student(Student &a)"<<endl;//分配内存空间this->name = new char[256];strcpy(this->name,name);this->age = age;}
private:char *name;int age;
};Student::Student(const char *name,int age=20) //name 记录的是 数据段.rodata 中的"张3" 内存空间起始地址
{cout<<"Student(char *name,int age=20)"<<endl;//分配内存空间this->name = new char[256];strcpy(this->name,name);this->age = age;
}Student::~Student()
{cout<<"~Student()"<<endl;delete []this->name;
}int main()
{//根据参数调用普通构造函数Student mya("张3");//如果是在定义一个对象的时候通过另一个对象来初始化,那么会调用拷贝构造函数//Student myb(mya);Student myb = mya;//打印内存空间的地址cout<<"mya.name:"<<static_cast<const void *>(mya.name)<<endl;cout<<"myb.name:"<<static_cast<const void *>(myb.name)<<endl;return 0;
}

4、什么时候需要自己定义拷贝构造函数
当类的数据成员中 有指针成员的时候,需要申请内存空间

5、什么时候会调用到拷贝构造函数
在定义一个对象通过另一个对象来初始化,那么会调用拷贝构造函数

6、深拷贝 和 浅拷贝
浅拷贝:只拷贝对象本身空间里面的内容
深拷贝:拷贝对象本身空间内容的同时,还要分配成员指向的堆空间并且进行拷贝

二、类的组合

1、概念
一个类的对象作为另外一个类的数据成员。
也就是说,两个及以上相互独立的类能够放在一起,然后通过一个类就可以调用另一个类的对象从而调用另一个类的功能。
2、案例
一台电脑computer和一台打印机DaYinJi两个独立的类,computer有显示、算数,DaYinJi有打印功能,当组合在一起后,对于computer类就可以调用打印机的打印功能。

#include <iostream>using namespace std;//打印机类
class DaYinJi{
public:DaYinJi(){cout<<"DaYinJi()"<<endl;}~DaYinJi(){cout<<"~DaYinJi()"<<endl;}DaYinJi(int data):a(data){cout<<"DaYinJi(int data)"<<endl;}int a;void DaYin(){cout<<"正在打印....."<<endl;}
};class Demo{
public:Demo(int c){cout<<"Demo()"<<endl;}~Demo(){cout<<"~Demo()"<<endl;}
};//类的组合
/*
需要解决的问题??
1、在类的组合中,如何指定 内嵌对象的构造函数???   在本类的构造函数的初始化列表上指定内嵌对象的构造函数
2、构造函数的执行顺序 是  打印机类的构造函数  再到  电脑类的构造函数
*///电脑类
class Computer{public://在本类的构造函数的初始化列表上指定内嵌对象的构造函数Computer():e(2000),d(1000){cout<<"Computer()"<<endl;}~Computer(){cout<<"~Computer()"<<endl;}void exec(){d.DaYin();}
private://私有成员  是 另一个类的对象   --如何去指定 对象的构造函数???//内嵌对象//如果有多个内嵌对象,那么多个内嵌对象的  构造函数的执行顺序跟  定义的先后顺序有关    跟  构造函数指定的先后顺序 无关DaYinJi d;Demo e;
};int main()
{//实例化一个电脑类的对象Computer c1;//我要用电脑打印文件c1.exec();return 0;
}

3、构造函数调用顺序

在构造函数的列表中指定内嵌对象的构造函数的形式 
如果不指定内嵌对象构造函数的形式,则调用的默认构造函数 
顺序:内嵌对象 ==》本类 
多个内嵌对象 顺序:按照定义内嵌对象的先后顺序调用内嵌对象的构造函数

【注意】不能在构造函数的初始化列表中初始化内嵌对象成员

4、析构函数调用顺序

顺序:本类==》内嵌对象

练习1:设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系(判断该点是在圆内、圆外还是圆上)。

#include <iostream>using namespace std;//点类
class Point
{
public://设置X坐标void setX(int x) {m_x = x;}//获取X坐标int getX() {return m_x;}//设置Y坐标void setY(int y){m_y = y;}//获取Y坐标int getY(){return m_y;}  
private:int m_x;int m_y;
};  
//设置一个圆类Circle
class Circle
{
public://设置半径void setR(int r){m_R = r;}//获取半径int getR(){return m_R;}//设置圆心void setCenter(Point center) {m_center = center;}//获取圆心Point getCenter()   //m_center是Piont类的数据{return m_center;}  
private:int m_R;//在类中可以让另一个类 作为本类中的成员--与结构体相似Point m_center;
};//判断点和圆的关系
void isInCircle(Circle &c, Point &p)
{if ((p.getX() - c.getCenter().getX()) * (p.getX() - c.getCenter().getX()) + (p.getY() - c.getCenter().getY()) * (p.getY() - c.getCenter().getY()) == c.getR() * c.getR())cout << "点在圆上" << endl;else if ((p.getX() - c.getCenter().getX()) * (p.getX() - c.getCenter().getX()) + (p.getY() - c.getCenter().getY()) * (p.getY() - c.getCenter().getY()) > c.getR() * c.getR())cout << "点在圆外" << endl;else cout << "点在圆内" << endl;
}int main()
{//创建并设置点P1Point P1;P1.setX(10);P1.setY(9);//创建并设置点P2--圆心Point P2;P2.setX(10);P2.setY(0);//设置圆C1Circle C1;C1.setR(10);C1.setCenter(P2);isInCircle(C1, P1);system("pause");return 0; 
}

三、类的继承

1、概念
新的类(子类)从已知的类(父类)中得到已有的特征的过程

新类叫派生类/子类 
已知的类叫基类/父类 

2、作用
继承可以减少重复的代码。比如父类已经提供的方法,子类可以直接使用,不必再去实现。

class 子类名:继承方式 父类(继承方式省略默认是私有继承)
{子类成员
};

4、例子

#include<iostream>using namespace std;//父类/基类
class Base{public: Base(){cout<<"Base()"<<endl;}~Base(){cout<<"~Base()"<<endl;}void setValue(int value){base_a = value;}int getValue(){return base_a;}void showValue(){cout<<"base_a:"<<base_a<<endl;}int base_a;
};class Child:public Base{public:Child(){cout<<"Child()"<<endl;}~Child(){cout<<"~Child()"<<endl;}    
};int main()
{Child mya;//直接调用基类的函数成员mya.setValue(100);mya.showValue();return 0;
}

5、什么情况下用继承
基类和派生类之间存在is-a关系
6、总结

  • 在派生类的构造函数的初始化列表中指定基类的构造函数
  • 构造函数调用顺序:基类–》派生类
  • 析构函数调用顺序:派生类–》基类
    练习2:设计一个人的类(基类),再分别设计一个学生类(子类) 和 教师类 (子类)单继承 人类
    人类:
    属性:姓名、年龄、性别
    方法:吃饭、睡觉
    学生类:
    属性:姓名、年龄、性别、分数、学号
    方法:吃饭、睡觉、打游戏、学习
    教师类:
    属性:姓名、年龄、性别、教龄、工作类别(教的是语文还是数学还是英语)
    方法:吃饭、睡觉、学习、备课

四、继承方式
继承方式有三种: 公有继承(public)、保护继承(protected)、私有继承(private)
在这里插入图片描述
上面表格权限是基类中的成员继承到子类后的成员权限

  • 如果派生类在继承基类的时候选择 公有继承(public)
    那么基类的公有成员就是在派生类中也是充当公有成员,可以直接在派生类的内部和外部使用
    那么基类的保护成员就是在派生类中也是充当保护成员,可以在派生类的内部使用,但是不能外部使用
    那么 基类的私有成员可以继承,但是不能直接访问,可以通过基类的公有方法和保护方法间接访问

  • 如果派生类在继承基类的时候选择 保护继承(protected)
    那么基类的公有成员就是在派生类中是充当保护成员,可以在派生类的内部使用,但是不能外部使用
    那么基类的保护成员就是在派生类中是充当保护成员,可以在派生类的内部使用,但是不能外部使用
    那么 基类的私有成员可以继承,但是不能直接访问,可以通过基类的公有方法和保护方法间接访问

  • 如果派生类在继承基类的时候选择 私有继承(private)
    那么基类的公有成员就是在派生类中是充当私有成员,可以在派生类的内部使用,但是不能外部使用
    那么基类的保护成员就是在派生类中是充当私有成员,可以在派生类的内部使用,但是不能外部使用
    那么 基类的私有成员可以继承,但是不能直接访问,可以通过基类的公有方法和保护方法间接访问

#include<iostream>using namespace std;//基类
class Base{public:Base(int data=100):baseData(data){cout<<"Base()"<<endl;}~Base(){cout<<"~Base()"<<endl;}void setData(int data){baseData = data;}int getData(){return baseData;}
protected:void showData(){cout<<"baseData:"<<baseData<<endl;}
private:int baseData;
};class Child:private Base{public:Child(int data=20):Base(data){showData();cout<<"Child()"<<endl;}~Child(){cout<<"~Child()"<<endl;}
};
int main()
{Child mya(200);//mya.setData(1000);return 0;
}

四、总结:

类的组合(has-a)和类的继承(is-a)是面向对象编程中两种重要的关系,它们在概念、使用场景、实现方式等方面存在显著的区别。以下是这两者的详细对比:

一、概念区别
类的组合(has-a):
指的是一个类(或对象)包含另一个类的对象作为其属性。这种关系强调的是“拥有”或“包含”的关系。
例如,一个汽车类可以包含一个发动机类的对象作为属性,表示汽车拥有发动机。
类的继承(is-a):
指的是一个类(子类)继承另一个类(父类)的属性和方法。这种关系强调的是“是一种”的关系。
例如,一个猫类可以继承一个动物类,表示猫是动物的一种。
二、使用场景区别
类的组合:
当一个类需要复用另一个类的功能,但又不希望与其产生过于紧密的联系时,使用组合。
组合关系有助于降低类之间的耦合度,提高系统的灵活性和可维护性。
例如,在设计一个图形界面时,一个窗口类可以包含多个按钮类的对象,而不需要通过继承来实现。
类的继承:
当一个类需要继承另一个类的属性和方法,并且这些属性和方法对于子类来说具有普遍意义时,使用继承。
继承关系有助于实现代码的重用和扩展,但也可能导致类之间的耦合度过高,增加系统的复杂性。
例如,在设计一个动物类库时,可以使用继承来定义不同种类的动物,如猫、狗等,它们都继承自动物类。
三、实现方式区别
类的组合:
在组合类中,通过属性来持有另一个类的对象。
可以通过这个属性来调用被包含类的方法,但不需要继承其所有方法和属性。
组合关系通常是在运行期确定的,因为可以在运行时动态地创建和销毁被包含类的对象。
类的继承:
在继承关系中,子类继承父类的所有非私有属性和方法(在Java等语言中,私有属性和方法不能被继承)。
子类可以覆盖(Override)父类的方法,以提供自己的实现。
继承关系在编译期就已经确定,因为子类需要知道父类的所有接口才能正确地实现它们。
四、其他区别
耦合度:组合关系是一种松耦合关系,而继承关系则是一种紧耦合关系。松耦合关系有助于降低系统各部分之间的依赖程度,提高系统的灵活性和可维护性。
多态性:在继承关系中,可以实现类型的回溯(即子类对象可以被当作父类对象来使用),从而实现多态性。而在组合关系中,通常不具备这种特性。
设计原则:在面向对象设计中,通常建议优先考虑组合而不是继承。因为组合关系更加灵活,可以更好地应对变化。而继承关系则可能导致系统结构过于复杂和僵化。
综上所述,类的组合和类的继承在面向对象编程中各有其独特的优势和适用场景。在实际应用中,应根据具体需求和设计原则来选择合适的关系来实现代码的组织和复用。

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

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

相关文章

目标检测入门:3.目标检测损失函数(IOU、GIOU、GIOU)

目录 一、IOU 二、GIOU 三、DIOU 四、DIOU_Loss实战 在前面两章里面训练模型时&#xff0c;损失函数都是选择L1Loss&#xff08;平均绝对值误差&#xff08;MAE&#xff09;&#xff09;损失函数&#xff0c;L1Loss损失函数公式如下: 由公式可知&#xff0c;L1Loss损失函数…

为PPT加密:如何设置和管理“打开密码”?

在保护演示文稿的内容时&#xff0c;给PPT文件设置“打开密码”是一个简单而有效的方法。今天一起来看看如何设置和管理PPT文件的“打开密码”吧&#xff01; 一、设置PPT“打开密码” 首先&#xff0c;打开需要加密的PPT文件&#xff0c;点击左上角的“文件”选项卡&#x…

大数据------JavaWeb------JSP(完整知识点汇总)

JSP 定义 JSP&#xff08;Java Server Pages&#xff09;&#xff0c;即Java服务端页面。它是一种动态的网页技术&#xff0c;其中可以定义HTML、CSS、JS等静态内容&#xff0c;还可以定义Java代码的动态内容JSP HTML Java 说白了JSP就是一个页面&#xff0c;它既可以写HTML标…

iOS App 测试环境升级,遇到的问题以及解决方法

iOS App 测试环境升级&#xff0c;遇到的问题以及解决方法 Mac 实体机升级到 Sonima 14.5 Xcode 升级到 15.3 问题1&#xff1a; Xcode 编译 WebDriverAgent 失败 尝试下载 最新版本的WDA 源码编译&#xff0c;可以编译成功。 问题2&#xff1a;具体坐标直接点击的代码都会报错…

亮相2024世界人工智能大会,扫描全能王AIGC“黑科技”助力敦煌遗书数字化修复

7月4日&#xff0c;2024年世界人工智能大会&#xff08;简称“大会”&#xff09;在上海举行。这次这场科技与创新的盛会上&#xff0c;一张古朴、典雅的卷轴吸引了众人的目光。这张被修复的卷轴脱胎于敦煌遗书系列古籍&#xff0c;在被机器拍摄扫描后&#xff0c;卷轴上脏污、…

新手教学系列——【Ubuntu】SSH配置详解

在使用Ubuntu进行远程管理和开发时,SSH(Secure Shell)是必不可少的工具。SSH不仅提供安全的远程登录功能,还支持安全的文件传输和端口转发。然而,有时我们可能会遇到SSH连接中断的问题。本文将详细介绍如何配置SSH以提高其稳定性,并解释关键配置项。 为什么会出现SSH连接…

实验二 图像的代数运算

一、实验目的&#xff1a; 1&#xff0e;了解图像的算术运算在数字图像处理中的初步应用。 2&#xff0e;体会图像算术运算处理的过程和处理前后图像的变化。 二、实验内容&#xff1a; 1&#xff0e;图像的加法运算 图像相加一般用于对同一场景的多幅图像求平均效果&…

Qt实现检测软件是否多开

Qt实现检测软件是否多开 在桌面软件开发中&#xff0c;软件通常要设置只允许存在一个进程&#xff0c;像一些熟知的音乐软件&#xff0c;QQ音乐这种。而这些软件在限制只有一个进程的同时&#xff0c;通常还会有双击桌面图标唤醒已运行的后台进程的功能。关于双击桌面唤醒已运…

【server】3、注册中心与配置中心

1、服务注册与发现 1.1、consul 1.1.1 是什么 官网&#xff1a; Consul by HashiCorp spring-cloud-consul: Spring Cloud Consul :: Spring Cloud Consul gitHub 官网 &#xff1a;GitHub - hashicorp/consul: Consul is a distributed, highly available, and data cent…

Wayfair EDI项目案例

Wayfair是一家成立于2002年的美国电子商务公司&#xff0c;专注于家居用品的销售。其总部位于马萨诸塞州波士顿。Wayfair提供广泛的产品种类&#xff0c;包括家具、装饰品、家居用品和室外用品等。通过其网站和移动应用程序&#xff0c;顾客可以方便地浏览和购买所需的家居产品…

2024最新中级会计职称考试全科题库资料。

1.根据消费税法律制度的规定&#xff0c;下列各项中&#xff0c;属于消费税征税范围的是&#xff08;&#xff09;。 A.汽车轮胎 B.食用酒精 C.铂金首饰 D.体育上用的发令纸 答案&#xff1a;C 解析&#xff1a;选项ABD均不属于消费税的征税范围。 2.甲企业&#xff08;…

抬头显示器HUD原理及特性

HUD基本原理 抬头数字显示仪(Head Up Display)&#xff0c;又叫平视显示系统&#xff0c;它的作用&#xff0c;就是把时速、导 航等重要的行车信息&#xff0c;投影到驾驶员前风挡玻璃上&#xff0c;让驾驶员尽量做到不低头、不转头 就能看行车信息。 HUD成像为离轴三反的过程&…

MATLAB——循环语句

一、for end语句 在该语法中&#xff0c;循环变量是用于迭代的变量名&#xff0c;它会在每次循环迭代中从向量或矩阵中取出一列的值。数值向量或者矩阵则表示了循环变量可以取值的范围&#xff0c;通常根据实际需要事先给定。一旦循环变量遍历完数值向量或者矩阵中的所有值&…

【配置网络和使用ssh服务】

文章目录 一、配置文件二、配置网络1.使用系统菜单配置网络2.通过网卡配置文件配置网络3.使用图形界面配置网络4.使用nmcli命令配置网络 三、配置远程控制服务1.配置sshd服务2.安全密钥验证3.远程传输命令 一、配置文件 跟网络有关的主要配置文件如下&#xff1a; /etc/host.c…

failed to lazily initialize a collection of role,解决Hibernate查询报错

Hibernate报错&#xff1a; org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.jiuqi.gov.common.attatchment.entity.AttachmentEntity.properties, could not initialize proxy - no Session at org.hibernate.co…

20240705 每日AI必读资讯

&#x1f4da;Retool 刚刚发布了最新2024上半年《人工智能现状报告》 - 收集了约750名技术人员的意见 - 包括开发者、数据团队和各行业的领导者&#xff0c;了解如何利用人工智能产生真正的影响。 &#x1f517; 2024上半年《人工智能现状报告》Retool刚刚发布了最新-CSDN b…

【DataSophon】DataSophon1.2.1服务组件开启 kerberos

目录 一、DataSophon是什么 1.1 DataSophon概述 1.2 架构概览 1.3 设计思想 二、集成组件 三、环境准备 四、安装kerberos服务 4.1 Zookeeper 4.2 HDFS 4.3 HBase 4.4 YARN 4.5 hive 【DataSophon】大数据管理平台DataSophon-1.2.1安装部署详细流程-CSDN博客 【Da…

初探前端世界:网页基本结构入门指南

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和<CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 &#x1f451;认识前端和网页&#x1f353;1 什么是网页&#x1f353;2 …

部署redis集群哨兵模式

部署redis集群哨兵模式 前言主要功能工作机制 一、虚拟机部署1、安装2、改配置1、redis.conf2、sentinel.conf3、起服务4、停redis-server服务&#xff0c;验证sentinel 3、脚本1. sentinel notification-script2. sentinel reconfig-script3. sentinel client-reconfig-script…

3个让你爽到爆炸的学习工具

We OCR WeOCR 是一个基于浏览器的文字识别工具&#xff0c;用户可以通过上传图片来识别其中的文本信息。它是一个渐进式网络应用程序&#xff08;PWA&#xff09;&#xff0c;可以在浏览器中离线使用。WeOCR 是开源的&#xff0c;并且基于 Tesseract OCR 引擎开发。用户无需在本…