C++学习路线(二十二)

构造函数

构造函数作用

在创建一个新的对象时,自动调用的函数,用来进行“初始化”工作:对这个对象内部的数据成员进行初始化。

构造函数特点

1.自动调用(在创建新对象时,自动调用)

2.构造函数的函数名,和类名相同

3.构造函数没有返回类型

4.可以有多个构造函数(即函数重载形式)

构造函数种类

默认构造函数

自定义的构造函数

拷贝构造函数

赋值构造函数

默认构造函数

没有参数的构造函数,称为默认构造函数。

合成的默认构造函数

但没有手动定义默认构造函数时,编译器自动为这个类定义一个构造函数

1)如果数据成员使用了“类内初始值”,就使用这个值来初始化数据成员。

2)否则,就使用默认初始化(实际上,不做任何初始化)

#include <iostream>
using namespace std;class Human {
public:Human(){cout << "Human constructor called." << endl;}
};
int main() {Human p1;return 0;
}

只要手动定义了任何一个构造函数,编译器就不会生成“合成的默认构造函数”一般情况下,都应该定义自己的构造函数,不要使用“合成的默认构造函数”【仅当数据成员全部使用了“类内初始值”,才宜使用“合成的默认构造函数”】 

赋值构造函数

#include <iostream>
using namespace std;class Person {
public:void setAddr(char* p) {addr = p;}void description() const {cout << "Address: " << addr << endl;}
private:char* addr;
};int main() {char* str = new char[100] {"123 Main St"};Person p1;p1.setAddr(str);Person p2;p2 = p1; // 执行浅拷贝p1.description(); // 应该打印: Address: 123 Main Stp2.description(); // 应该也打印: Address: 123 Main St// 修改原始字符串,并查看 p1 和 p2 是否受到影响strncpy_s(str,100 ,  "456 Elm St" , _TRUNCATE );p1.description(); // 现在打印: Address: 456 Elm Stp2.description(); // 也打印: Address: 456 Elm Stdelete[] str; // 记得删除动态分配的内存return 0;
}

你执行 p2 = p1; 这一行时,默认情况下编译器会使用浅拷贝(shallow copy)。这意味着如果你的类中有指针或者持有对其他资源的引用的话,那么这些资源会被同样的引用到新的对象中去,而不是创建独立的副本。

我们可以自定义运算符重载Person& operator=(const Person& person)来实现深拷贝

#include <iostream>
using namespace std;class Person {
public:void setAddr(char* p) {addr = p;}void description() const {cout << "Address: " << addr << endl;}Person& operator=(const Person& p) {//防止对象自身赋值if (this == &p) return *this;//如果执行f2 = f1//就会调用f2.operator=(f1)//如果有必要 先释放自己的动态资源delete[] addr;//再拷贝p的动态资源到自己  addr = new char[strlen(p.addr) + 1];strcpy_s(addr, strlen(p.addr) + 1, p.addr);//返回对象本身的引用,是为了方便能够链式处理//f1 = f2 = f3return *this;}~Person() {delete[] addr;}
private:char* addr;
};int main() {char* str = new char[100] {"123 Main St"};Person p1;p1.setAddr(str);Person p2;p2 = p1; // 执行浅拷贝p1.description(); // 应该打印: Address: 123 Main Stp2.description(); // 应该也打印: Address: 123 Main St// 修改原始字符串,并查看 p1 和 p2 是否受到影响strncpy_s(str,100 ,  "456 Elm St" , _TRUNCATE );p1.description(); // 现在打印: Address: 456 Elm Stp2.description(); // 也打印: Address: 456 Elm Stdelete[] str; // 记得删除动态分配的内存return 0;
}

拷贝构造函数

#include <iostream>
using namespace std;class Person {
public:Person() {age = 0;name = "";}Person(const Person& p) {cout << "Copy constructor called." << endl;age = p.age;name = p.name;}void setAge(int a) {age = a;}void setName(string n) {name = n;}
private:int age;string name;
};int main() {Person p1;p1.setAge(25);p1.setName("John");Person p2(p1);Person p3 = p1;return 0;
}

合成的拷贝构造函数

        是指当类中没有显式定义拷贝构造函数时,编译器自动为该类生成的一个默认拷贝构造函数。这个自动生成的拷贝构造函数会执行成员变量的浅拷贝(shallow copy),即将源对象的每个成员变量的值直接复制到新创建的对象中。 简单来说,合并的拷贝构造函数是编译器在类定义中没有显式提供拷贝构造函数时自动提供的一个默认实现。这个默认实现会逐成员地复制源对象的值到新对象中,但它不会处理动态分配的内存(如指针指向的内存)的深拷贝(deep copy)问题,这可能会导致资源泄露或双重释放等问题。

合成的拷贝构造函数都是浅拷贝 下面给出一个浅拷贝的例子。

#include <iostream>
using namespace std;class Person {
public:void mallocAdress() {address = new char[100];}~Person() {if(address) delete[] address;}void print() {printf("address: %p\n", address);}
private:char* address = nullptr;
};int main() {Person p1;p1.mallocAdress();Person p2 = p1;Person p3(p1);p1.print();p2.print();return 0;
}

要解决合并的拷贝函数,我们可以自己定义一个拷贝构造函数

#include <iostream>
using namespace std;class Person {
public:void mallocAdress() {address = new char[100];}~Person() {if(address) delete[] address;}void print() {printf("address: %p\n", address);}Person(const Person& p) {address = new char[100];}
private:char* address = nullptr;
};int main() {Person p1;p1.mallocAdress();Person p2 = p1;Person p3(p1);p1.print();p2.print();return 0;
}
什么时候调用拷贝构造函数

1.调用函数时,实参是对象,形参不是引用类型

#include <iostream>
using namespace std;class MyClass {
public:MyClass(int val) {this->val = val;cout << "Constructor called" << endl;}MyClass(const MyClass& obj) {cout << "Copy constructor called" << endl;this->val = obj.val;}int val;
};void func(MyClass obj) {cout << "Value of obj is " << obj.val << endl;
}int main() {MyClass obj1(10);func(obj1);return 0;
}

2.函数的返回类型是类,而且不是引用类型

#include <iostream>class MyClass {
public:MyClass(int val) : value(val) {std::cout << "MyClass constructor called." << std::endl;}MyClass(const MyClass& other) : value(other.value) {std::cout << "Copy constructor called." << std::endl;}int value;
};
MyClass returnObject() {MyClass temp(20);return temp; // 返回局部变量会调用拷贝构造函数
}
int main() {MyClass returned = returnObject(); // 这里也会调用拷贝构造函数std::cout << "Returned object value: " << returned.value << std::endl;return 0;
}

虽然会因为RVO优化,不调用MyClass的拷贝构造函数

3.对象数组的初始化列表中,使用对象。

#include <iostream>class MyClass {
public:MyClass(int val) : value(val) {std::cout << "MyClass constructor called." << std::endl;}MyClass(const MyClass& other) : value(other.value) {std::cout << "Copy constructor called." << std::endl;}int value;
};int main() {MyClass source(30);MyClass array[3] = { source, source, source }; // 这里会三次调用拷贝构造函数for (int i = 0; i < 3; ++i) {std::cout << "Array[" << i << "] value: " << array[i].value << std::endl;}return 0;
}

类和基本数据不同(int , float , double , long , long long)

类的构成:方法和数据

#include <iostream>
using namespace std;
class Human {
public:int age;string name;void print() {cout << "Name: " << name << ", Age: " << age << endl;}Human() {cout << "Constructor called." << endl;}Human(const Human& h) {cout << "Copy constructor called." << endl;}Human& operator=(const Human& h) {cout << "Assignment operator called." << endl;return *this;}~Human() {cout << "Destructor called." << endl;}
};
int main() {Human h1;cout << "---" << endl;Human* h2 = &h1;return 0;
}

上面以指针的形式来进行初始化的话不会调用拷贝

如果某数据成员使用类内初始值,同时又在构造函数中进行了初始化

那么以构造函数中的初始化为准

相当于构造函数中的初始化,会覆盖对应的类内初始值

#include <iostream>class MyClass {
public:MyClass() : value(10) { // 类内初始化std::cout << "Default constructor called." << std::endl;}MyClass(int val) : value(val) { // 构造函数初始化std::cout << "Constructor with initial value called." << std::endl;}MyClass(const MyClass& other) : value(other.value) { // 拷贝构造函数std::cout << "Copy constructor called." << std::endl;}void printValue() const {std::cout << "Value is: " << value << std::endl;}private:int value = 5; // 类内初始值
};int main() {MyClass obj1; // 使用类内默认构造函数obj1.printValue(); // 输出 Value is: 10MyClass obj2(20); // 使用构造函数初始化obj2.printValue(); // 输出 Value is: 20return 0;
}

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

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

相关文章

react18中的jsx 底层渲染机制相关原理

jsx 底层渲染机制 渲染 jsx 时&#xff0c;会先解析 jsx&#xff0c;生成一个虚拟 dom(virtual dom)。然后将虚拟 dom 渲染成真实 dom。如果 jsx 中包含事件&#xff0c;会将事件绑定到真实 dom 上。 虚拟 dom 对象&#xff0c;是框架内部构建的一套对象体系&#xff0c;对象…

无废话、光速上手 React-Router

React-Router React Router 是一个用于 React 应用的声明式路由库。它允许开发者通过组件化的方式定义应用的路由结构&#xff0c;使得路由管理更加直观和可维护 安装 pnpm i react-router-dom定义路由 定义路由有两种方式&#xff0c;分别是对象路由和路由组件&#xff0c…

AIGC时代 | 从零到一,打造你的专属AI Chat应用!

文章目录 目标功能概要&#xff08;1&#xff09;Chat 交互界面&#xff08;2&#xff09;流式接口&#xff08;3&#xff09;多轮会话&#xff08;4&#xff09;打字效果 系统架构&#xff08;1&#xff09;大模型服务层&#xff08;2&#xff09;应用服务层&#xff08;3&…

深入解析东芝TB62261FTG,步进电机驱动方案

TB62261FTG是一款由东芝推出的两相双极步进电机驱动器&#xff0c;采用了BiCD工艺&#xff0c;能够提供高效的电机控制。这款芯片具有多种优秀的功能&#xff0c;包括PWM斩波、内置电流调节、低导通电阻的MOSFET以及多种步进操作模式&#xff0c;使其非常适合用于需要精确运动控…

微信小程序的日期区间选择组件的封装和使用

组件化开发是一种将大型软件系统分解为更小、更易于管理和复用的独立模块或组件的方法。这种方法在现代软件开发中越来越受到重视&#xff0c;尤其是在前端开发领域。微信小程序的日期区间选择组件的使用 wxml 代码 <view><view bind:tap"chooseData">…

第一个Qt程序

创建项目 进入ui界面拖一个按钮 在头文件中添加函数说明 #ifndef HELLO_H #define HELLO_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class Hello; } QT_END_NAMESPACEclass Hello : public QMainWindow {Q_OBJECTpublic:Hello(QWidget *parent nullpt…

上海亚商投顾:沪指缩量调整 NMN概念股逆势大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 市场全天震荡调整&#xff0c;三大指数午后一度跌超1%&#xff0c;北证50指数则涨超4%&#xff0c;北交所个股…

前端发送请求格式

1.multipart/form-data格式发送请求参数 什么时候用&#xff1a; 当后端API要求以表单的形式接收数据时&#xff0c;比如<input type"text" name"username">和<input type"password" name"password">&#xff0c;这些数据…

html全局属性、框架标签

常用的全局属性&#xff1a; 属性名含义id 给标签指定唯一标识&#xff0c;注意&#xff1a;id是不能重复的。 作用&#xff1a;可以让label标签与表单控件相关联&#xff1b;也可以与css、JavaScript配合使用。 注意&#xff1a;不能再以下HTML元素中使用&#xff1a;<hea…

自动化部署-01-jenkins安装

文章目录 前言一、下载安装二、启动三、问题3.1 jdk版本问题3.2 端口冲突3.3 系统字体配置问题 四、再次启动五、配置jenkins5.1 解锁5.2 安装插件5.3 创建管理员用户5.4 实例配置5.5 开始使用5.6 完成 总结 前言 spingcloud微服务等每次部署到服务器上&#xff0c;都需要本地…

鸿蒙到底是不是纯血?到底能不能走向世界?

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 2016年5月鸿蒙系统开始立项。 2018年美国开始经济战争&#xff0c;其中一项就是制裁华为&#xff0c;不让华为用安卓。 2019年8月9日华为正式发布鸿蒙系统。问题就出在这里&#xff0c;大家可以仔细看。 安卓一…

从零开始学五笔(三):横区字根

从 1 区开始讲解字根&#xff1a; 先介绍按键的区位号、口诀内容、口诀说明然后列每个字根能组成什么汉字&#xff0c;难拆字将用中括号标出 ‍ G 键 区位号&#xff1a;11 口诀&#xff1a;王旁青头戋&#xff08;兼&#xff09;五一 说明&#xff1a; 王旁&#xff1a…

VUE, element-plus, table分页表格列增加下拉筛选多选框,请求后台

简介 为了方便表格查询时可以筛选列的值&#xff0c;需要给列增加筛选框&#xff08;多选框&#xff09;&#xff0c;element-plus提供了列的filter字段&#xff0c;但是基于表格数据的筛选&#xff0c;不会重新请求后台&#xff0c;而且当前表格数据有多少个条目&#xff0c;…

荣耀MagicOS 9.0发布会及开发者大会丨一图读懂应用服务及商业合作分论坛

更多优质流量变现服务&#xff0c;可点击荣耀广告变现服务查看&#xff1b; 荣耀远航计划——应用市场【耀闪行动】全新上线&#xff0c;更多激励及资源扶持可点击荣耀应用市场耀闪行动查看。

香港大学联合上海AI LAB,提出首个人机交互一体化大模型

导读&#xff1a; 具身智能为人与机器人的交互带来了更多便利&#xff0c;利用大语言模型&#xff08;LLMs&#xff09;的推理能力&#xff0c;能够将人类的语言指令逐步转换为机器人可以理解的指令信号。 然而&#xff0c;由于缺乏环境信息作为机器人理解环境和人类指令的上…

FPGA开发verilog语法基础1

文章目录 主体内容1.1 逻辑值1.2 数字进制格式1.3 数据类型1.3.1 寄存器类型1.3.2 线网类型1.3.3 参数类型1.3.4 存储器类型 参考资料 主体内容 1.1 逻辑值 1&#xff0c;逻辑0&#xff0c;表示低电平 2&#xff0c;逻辑1&#xff0c;表示高电平 3&#xff0c;逻辑X&#xff0…

网站安全问题都有哪些,分别详细说明

网站安全问题涉及多个方面&#xff0c;以下是一些常见的网站安全问题及其详细说明&#xff1a; 数据泄露 问题描述&#xff1a;数据泄露是指网站存储的用户敏感信息&#xff08;如用户名、密码、信用卡信息等&#xff09;被非法获取。黑客可能通过SQL注入、XSS攻击等手段窃取这…

学习分布式系统我来助你!【基本知识、基础理论、设计模式、应用场景、工程应用、缓存等全包含!】

基本知识 什么是分布式 分布式系统是一种通过网络连接多个独立计算机节点&#xff0c;共同协作完成任务的系统架构&#xff0c;具有高度的可扩展性、容错性和并发处理能力&#xff0c;广泛应用于大数据处理、云计算、分布式数据库等领域。 通俗来讲&#xff1a;分布式系统就…

git入门操作(2)

文章目录 git入门操作&#xff08;2&#xff09;git diff 查看差异git diff gitignore忽略文件1.在代码仓库创建这个文件2.添加对 log 文件过滤 连接远程仓库与ssh配置远程仓库和本地仓库关联步骤分支基本操作步骤命令&#xff1a; 合并冲突分支合并逻辑1.新建分支 dev&#xf…

ONLYOFFICE 文档8.2版本已发布:PDF 协作编辑、改进界面、性能优化等更新

ONLYOFFICE 在线编辑器最新版本已经发布&#xff0c;其中包含30多个新功能和500多个错误修复。阅读本文了解所有更新。 关于 ONLYOFFICE 文档 ONLYOFFICE 是一个开源项目&#xff0c;专注于高级和安全的文档处理。坐拥全球超过 1500 万用户&#xff0c;ONLYOFFICE 是在线办公领…