C++:类和对象(3)

目录

1.构造函数调用规则

2.深拷贝和浅拷贝

3.初始化列表

4.类对象作为类成员


1.构造函数调用规则

     默认情况下,C++编译器至少给类添加三个函数:

1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值的拷贝

     构造函数调用规则如下:

如果用户自己实现了有参构造函数,C++不会再提供无参构造函数,但是会提供默认拷贝构造如果用户自己实现了拷贝构造函数,C++不会提供任何构造函数

     比如:

     1.如果用户自己实构造函数,C++不会再提供无参构造函数,但是会提供默认拷贝构造

#include<iostream>
using namespace std;
class Person
{
public://有参构造函数Person(int age){_age = age;cout << "有参构造函数调用" << endl;}//析构函数~Person(){cout << "析构函数调用" << endl;}//拷贝构造函数Person(const Person& p){_age = p._age;cout << "拷贝构造函数调用" << endl;}int _age;};
int main()
{Person p;p._age = 18;Person p2(p);cout << "p2的年龄为:" << p2._age << endl;return 0;
}

     此时会显示报错:

类 "Person" 不存在默认构造函数

     因为我们写下了Person p,没有参数,要调用系统或者用户提供的无参构造函数,但因为我们实现了有参构造函数,系统就不会提供无参构造函数,同时我们自己也没有实现无参构造函数,就会报错。

      还是会提供默认构造,如果我们把Person p和拷贝构造函数代码删掉:

#include<iostream>
using namespace std;
class Person
{
public://有参构造函数Person(int age){_age = age;cout << "有参构造函数调用" << endl;}//析构函数~Person(){cout << "析构函数调用" << endl;}int _age;};
int main()
{Person p(18);Person p2(p);cout << "p2的年龄为:" << p2._age << endl;return 0;
}

     运行结果:

有参构造函数调用
p2的年龄为:18
析构函数调用
析构函数调用

      可以看到,系统会提供默认拷贝构造

2.如果用户自己实现了拷贝构造函数,C++不会提供任何构造函数

#include<iostream>
using namespace std;
class Person
{
public://拷贝构造函数Person(const Person& p){_age = p._age;cout << "拷贝构造函数调用" << endl;}//析构函数~Person(){cout << "析构函数调用" << endl;}int _age;};
int main()
{Person p;return 0;
}

     报错:

“Person”: 没有合适的默认构造函数可用

     可以看出,当我们自己实现了拷贝构造函数,如果我们自己不实现无参构造函数,系统就不会提供,有参构造函数系统本来就提供不了。

2.深拷贝和浅拷贝

     浅拷贝:简单的赋值拷贝操作

     深拷贝:在堆区重新申请空间,进行拷贝操作

#include<iostream>
using namespace std;
class Person
{
public://无参构造函数Person(){cout << "无参构造函数" << endl;}//有参构造函数Person(int age,int height){_age = age;_height=new int(height);cout << "有参构造函数调用" << endl;}//析构函数~Person(){//将堆区开辟的数据做释放操作if (_height != NULL){delete _height;_height = NULL;}cout << "析构函数调用" << endl;}int _age;int* _height;
};
int main()
{Person p1(18,180);cout << "p1的年龄为:" << p1._age <<"身高为:"<<*p1._height<<endl;Person p2(p1);cout << "p2的年龄为:" << p2._age <<"身高为:"<<*p2._height<<endl;return 0;
}

     我们想把身高这个数据开辟在堆区,就可以用new语法来创建,new创建之后返回一个指向该空间的指针,用_height来接收,同时堆区开辟的空间需要我们程序员手动来释放,上面给出了代码,运行看看怎么样,不好,出错了,这时候会出现报错:

已在 Project15.exe 中执行断点指令(__debugbreak()语句或类似调用)。

     这是为什么呢?其实是因为我们利用编译器提供的拷贝构造函数,做的是浅拷贝的操作

     p1和p2的指针都指向同一块空间,同一块空间释放两次肯定是不允许的,所以报错意料之中,浅拷贝带来的问题就是堆区的内存重复释放,要用深拷贝来解决

#include<iostream>
using namespace std;
class Person
{
public://无参构造函数Person(){cout << "无参构造函数" << endl;}//有参构造函数Person(int age,int height){_age = age;_height=new int(height);cout << "有参构造函数调用" << endl;}//自己实现拷贝构造函数,解决浅拷贝问题Person(const Person& p){_age = p._age;//_height=p._height;编译器提供的拷贝构造函数实现这段代码,就是直接赋值_height = new int(*p._height);cout<<"拷贝构造函数调用"<<endl;}//析构函数~Person(){//将堆区开辟的数据做释放操作if (_height != NULL){delete _height;_height = NULL;}cout << "析构函数调用" << endl;}int _age;int* _height;
};
int main()
{Person p1(18,180);cout << "p1的年龄为:" << p1._age <<"身高为:"<<*p1._height<<endl;Person p2(p1);cout << "p2的年龄为:" << p2._age <<"身高为:"<<*p2._height<<endl;return 0;
}

     自己再开辟一块堆区空间,将指针指向这块空间,释放的时候就不会再重复释放空间了。

3.初始化列表

     初始化列表语法用来初始化属性

语法:构造函数():属性1(值1),属性2(值2)...{}

     示例:

     传统的初始化操作:

class Person
{
public:Person(int a, int b, int c){_a = a;_b = b;_c = c;}int _a;int _b;int _c;
};

     初始化列表操作:

#include<iostream>
using namespace std;
class Person
{
public:Person(int a, int b, int c):_a(a),_b(b),_c(c){}int _a;int _b;int _c;
};
int main()
{Person p(10, 20, 30);cout << "_a=" << p._a << endl;cout << "_b=" << p._b << endl;cout << "_c=" << p._c << endl;return 0;
}

     输出:

_a=10
_b=20
_c=30

     使用初始化列表,函数体就可以写其他的内容,很灵活。

4.类对象作为类成员

    C++中类的成员可以是另一个类的对象,这种成员叫对象成员   

    比如:

class A{};
class B
{A a;
};

     那我们就有问题了,当我们创建B的对象时,A和B的构造函数和析构函数先执行谁的呢?让我们一起来看看

#include<iostream>
using namespace std;
class Phone
{
public:Phone(string Pname){_Pname = Pname;cout << "Phone的构造函数调用" << endl;}~Phone(){cout << "Phone的析构函数调用" << endl;}string _Pname;
};
class Person
{
public:Person(string name, string Pname):_name(name),_Phone(Pname){cout << "Person的构造函数调用" << endl;}~Person(){cout << "Person的析构函数调用" << endl;}string _name;//姓名Phone _Phone;//手机
};
int main()
{Person p("张三", "华为Mate60pro");cout << p._name << "拿着" << p._Phone._Pname << endl;return 0;
}

      输出:

Phone的构造函数调用
Person的构造函数调用
张三拿着华为Mate60pro
Person的析构函数调用
Phone的析构函数调用

     可以看到,当其他对象作为本类对象时,构造时先构造其他对象,再构造本类对象;析构的顺序是先调用本类对象的析构函数,再调用其他对象的析构函数。

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

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

相关文章

标签函数 - 打造JavaScript组件

&#x1f4e2; 鸿蒙专栏&#xff1a;想学鸿蒙的&#xff0c;冲 &#x1f4e2; C语言专栏&#xff1a;想学C语言的&#xff0c;冲 &#x1f4e2; VUE专栏&#xff1a;想学VUE的&#xff0c;冲这里 &#x1f4e2; CSS专栏&#xff1a;想学CSS的&#xff0c;冲这里 &#x1f4…

Flutter 混合开发 - aar打包

背景 项目接入 Flutter 后有两种方式&#xff0c;一种是 module 引入开发&#xff0c;一种是 aar 依赖开发。当前项目中在 Debug 阶段为了方便调试采用 module 开发&#xff0c;在发版时&#xff08;即 Release 阶段&#xff09;采用 aar 依赖引入。为了配合这种模式就需要在 …

高可用分布式部署Spark、完整详细部署教程

前言 Spark 是 UC Berkeley AMP Lab 开源的通用分布式并行计算框架。 Spark基于map reduce算法实现的分布式计算&#xff0c;拥有Hadoop MapReduce所具有的优点&#xff1b;但不同于MapReduce的是Job中间输出和结果可以保存在内存中&#xff0c;从而不再需要读写HDFS&#xff…

Spring AI和Ollama

概述 Spring AI 不仅提供了与 OpenAI 进行API交互&#xff0c;同样支持与 Ollama 进行API交互。Ollama 是一个发布在GitHub上的项目&#xff0c;专为运行、创建和分享大型语言模型而设计&#xff0c;可以轻松地在本地启动和运行大型语言模型。 Docker环境安装Ollama 1.获取D…

AIGC带给开发者的冲击

未来会有两种开发者&#xff0c;一种是会使用AIGC工具的开发者另一种是不会使用AIGC的开发者&#xff0c;AIGC的出现提高了开发效率和代码质量&#xff0c;对开发者意味着需要不断学习和适应新的技术和工作范式&#xff0c;开发者可以把更多的精力放在高级抽象的定义以及更高维…

JS的防抖和节流

目录 防抖 搜索框带来的问题 实现的思路 案例 封装防抖函数 节流 滚动条加载带来的问题 实现的思路 案例 封装节流函数 防抖 搜索框带来的问题 需求&#xff1a;根据输入框内容来请求数据 <!DOCTYPE html> <html lang"en"> <head><…

STHS34PF80人体存在传感器(1)----获取人体存在状态

STHS34PF80人体存在传感器.1--获取人体存在状态 概述视频教学样品申请完整代码下载主要特点硬件准备接口最小系统图生成STM32CUBEMX串口配置IIC配置CS设置串口重定向参考案例获取ID温度测量滤波方式智能识别算法使用块数据更新&#xff08;BDU&#xff09;功能设置ODR速率获取状…

Stable Diffusion架构的3D分子生成模型 GeoLDM - 测评与代码解析

之前&#xff0c;向大家介绍过3D分子生成模型 GeoLDM。 GeoLDM按照Stable Diffusion架构&#xff0c;将3D分子生成的扩散过程运行在隐空间内&#xff0c;优化了基于扩散模型的分子生成。可能是打开Drug-AIGC的关键之作。让精确控制分子生成有了希望。 详见&#xff1a;分子生成…

Python 中的==操作符 和 is关键字

Python是一种功能强大的通用编程语言&#xff0c;提供了各种比较值和对象的方法。其中包括操作符和is关键字&#xff0c;它们的用途不同&#xff0c;但由于它们有时可以达到相同的目的&#xff0c;所以经常会被混淆。在本文中&#xff0c;我们将深入研究和is之间的区别&#xf…

海外分支访问国内服务器系统慢怎么办?

在全球业务不断扩张的今天&#xff0c;企业面临着海外分支访问国内总部服务器系统慢的问题。为了解决这一挑战&#xff0c;我们引入了lxway全球系统专网产品&#xff0c;为企业提供高效、安全的全球网络连接方案。通过解析技术瓶颈和专网的优势&#xff0c;本文将揭示如何借助先…

设计模式之过滤器模式

目录 1.简介 2.过滤器的实现 2.1.过滤器的角色 2.2.类图 2.3.具体实现 3.过滤器模式的优点 4.过滤器模式的不足 5.适用的场景 1.简介 过滤器模式&#xff08;Filter Pattern&#xff09;或标准模式&#xff08;Criteria Pattern&#xff09;是一种结构型设计模式&…

【Python学习】Python学习3-变量类型

目录 【Python学习】Python学习3 前言变量赋值多个变量赋值标准数据类型Python Numbers(数字)Python List&#xff08;列表&#xff09;Python Tuple&#xff08;元组&#xff09;Python Dictionary&#xff08;字典&#xff09; Python数据类型转换总结参考 文章所属专区 Py…

【数据库原理】(9)SQL简介

一.SQL 的发展历史 起源&#xff1a;SQL 起源于 1970 年代&#xff0c;由 IBM 的研究员 Edgar F. Codd 提出的关系模型概念演化而来。初期&#xff1a;Boyce 和 Chamberlin 在 IBM 开发了 SQUARE 语言的原型&#xff0c;后发展成为 SQL。这是为了更好地利用和管理关系数据库。…

C#使用条件语句判断用户登录身份

目录 一、示例 二、生成 利用条件语句判断用户登录身份&#xff0c;根据用户登录身份的不同&#xff0c;给予相应的操作权限。 一、示例 主要用if语句及ComboBox控件。其中&#xff0c;ComboBox是窗体中的下拉列表控件&#xff0c;在使用ComboBox控件前&#xff0c;可以先向…

springboot实现ChatGPT式调用(一次调用,持续返回)

下边实现了一个持续返回100以内随机数的接口&#xff0c;在接口超时之前会每隔1秒返回一个随机数 GetMapping(value "/getRandomNum", produces MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter getRandomNum() {SseEmitter emitter new SseEmitter();Th…

【airsim】python控制airsim

使用airsim 1.8.1编译完成&#xff0c;进过block项目在cpp测试后&#xff0c;开始踩坑使用python。 使用AirSim\PythonClient\setup.py或者pip安装airsim。 python setup.py install或者 pip install airsim此时&#xff0c;windows电脑的环境信息 (air_py38) D:\code\Gith…

如何计算CAN通信波特率

目录 1、理论 2、实践 3、注意事项 在CAN总线系统中&#xff0c;波特率的计算是一个关键步骤&#xff0c;它确保网络上的所有设备能够以相同的速率进行通信。 1、理论 波特率的计算涉及到几个关键参数&#xff0c;包括CAN控制器的时钟频率、分频因子、以及位时间的不同部分…

vue icon 本地正常 线上打包失败变乱码

出现这个原因是因为sass解析的问题 Node版本高的话可以通过升级sass版本 并且配置vue.config规避这个问题 //给sass配置的东西 这个对应的版本是sass 1.39.0 本人node版本v14 升级sass版本后出现报错css: {loaderOptions: {scss: {additionalData: import "/styles/var…

JVM知识总结(简单且高效)

1. JVM内存与本地内存 JVM内存&#xff1a;受虚拟机内存大小的参数控制&#xff0c;当大小超过参数设置的大小时会报OOM。本地内存&#xff1a;本地内存不受虚拟机内存参数的限制&#xff0c;只受物理内存容量的限制&#xff1b;虽然不受参数的限制&#xff0c;如果所占内存超过…

软件工程概论------文件管理

目录 1.文件的相关概念 2.文件目录 3.位示图 4.索引文件 5.例题 1.文件的相关概念 文件:具有符号名的、在逻辑上具有完整意义的一组相关信息项的集合。 逻辑结构:有结构的记录式文件、无结构的流式文件。 物理结构: 连续结构、链接结构、索引结构、多个物理块的索引表。 …