c++:类和对象(2),对象的初始化和清理

目录

构造函数和析构函数

构造函数语法:类名(){}

 析构函数语法: ~类名  ()  {}

例子: 

构造函数的分类及调用

两种分类的方式:

三种调用方法:

括号法​编辑

显示法

隐式转换法 

拷贝构造函数调用时机

有三种:

1.使用一个已经创建完毕的对象来初始化一个新对象

2.值传递的方式给函数参数传值

3.以值方式返回局部对象

构造函数调用规则

深拷贝与浅拷贝

初始化列表 

基本格式: 

类对象作为类成员 

静态成员

静态成员变量

格式 

两种访问方式 

静态成员函数

 格式:

注意:


构造函数和析构函数

  • 构造函数:主要作用在于创造对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。
  • 析构函数:主要作用于在对象销毁前系统自动调用,执行一些清理工作。

构造函数语法:类名(){}

  1. 构造函数,没有返回值也不写void
  2. 函数名称和类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时会自动调用构造,无需手动调用,而且只会调用一次

 析构函数语法: ~类名  ()  {}

  1. 构造函数,没有返回值也不写void
  2. 函数名称和类名相同,在名称前加上符号~
  3. 析构函数不可以有参数,因此不可以发生重载
  4. 程序在对象销毁前会自动调用析构,无需手动调用,而且只会调用一次

例子: 

注意:构造和析构都是必须有的实现,如果我们自己不提供,编译器会提供一个空实现的构造和析构 。

我们做一个实验,将person p放在main函数中实现,此时,我们可以看到析构函数是在system("pause")后面实现的。说明:这个对象在main函数走完才会执行释放,销毁操作,出现析构操作。 


构造函数的分类及调用

两种分类的方式:

  • 按参数分为:有参构造和无参构造(默认构造)
  • 按类型分为:普通构造(不是拷贝构造的都叫普通构造)和拷贝构造

三种调用方法:

括号法

  • 注意:调用默认函数的构造,不加(),加上()编译器会认为是一个函数的声明。

显示法

  • 注意:不要利用拷贝构造函数 初始化匿名对象
  • 如:person(p3);

隐式转换法 


拷贝构造函数调用时机

有三种:

1.使用一个已经创建完毕的对象来初始化一个新对象

void test01()
{
	person p1(20);
	person p2(p1);
}

2.值传递的方式给函数参数传值

void dowork(person p)
{

}
void test02()
{
	person p;
	dowork(p);
}

3.以值方式返回局部对象

person dowork2()
{
    person p1;
    return p1;
}
void test03()
{
   person p=dowork2();
}

构造函数调用规则

默认情况下,c++编译器至少给一个类添加3个函数

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

构造函数调用规则如下:

  • 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

深拷贝与浅拷贝

  • 浅拷贝:简单的赋值拷贝操作
  • 深拷贝:在堆区重新申请空间,进行拷贝操作
  1. 浅拷贝(Shallow Copy):
    浅拷贝是一种简单的复制操作,它只复制对象的值(包括指针),而不会创建新的内存空间。浅拷贝会将原对象和新对象指向同一块内存地址。这意味着,如果一个对象的值发生变化,另一个对象也会受到影响。

  2. 深拷贝(Deep Copy):
    深拷贝是一种复制操作,它会创建一个全新的独立对象,并复制对象的值和指针所指向的数据。深拷贝会为新对象分配新的内存空间,使得原对象和新对象完全独立。这意味着,如果一个对象的值发生变化,另一个对象不会受到影响。

#include <iostream>

class MyClass 
{
public:
    int* data;

    // 构造函数
    MyClass(int value) 
    {
        data = new int;
        *data = value;
    }

    // 拷贝构造函数(浅拷贝)
    MyClass(const MyClass& other) 
    {
        data = other.data;
    }

    // 赋值运算符重载(浅拷贝)
    MyClass& operator=(const MyClass& other) 
    {
        if (this != &other) 
        {
            data = other.data;
        }
        return *this;
    }

    // 析构函数
    ~MyClass() 
    {
        delete data;
    }
};

int main() 
{
    // 创建对象1
    MyClass obj1(10);

    // 浅拷贝示例
    MyClass obj2_shallow = obj1;
    std::cout << "obj1.data: " << *obj1.data << std::endl;
    std::cout << "obj2_shallow.data: " << *obj2_shallow.data << std::endl;

    *obj1.data = 20;  // 修改obj1的值

    std::cout << "After modifying obj1.data..." << std::endl;
    std::cout << "obj1.data: " << *obj1.data << std::endl;
    std::cout << "obj2_shallow.data: " << *obj2_shallow.data << std::endl;
    // 输出结果显示obj2_shallow的值也被修改了,因为浅拷贝只是复制了指针而没有复制数据

    // 深拷贝示例
    MyClass obj3_deep(obj1);
    std::cout << "obj1.data: " << *obj1.data << std::endl;
    std::cout << "obj3_deep.data: " << *obj3_deep.data << std::endl;

    *obj1.data = 30;  // 修改obj1的值

    std::cout << "After modifying obj1.data..." << std::endl;
    std::cout << "obj1.data: " << *obj1.data << std::endl;
    std::cout << "obj3_deep.data: " << *obj3_deep.data << std::endl;
    // 输出结果显示obj3_deep的值没有被修改,因为深拷贝创建了新的内存空间来存储数据

    return 0;
}

初始化列表 

  1. 效率更高:使用初始化列表可以直接在对象构造时初始化成员变量,而不是在构造函数体内逐个赋值。这样可以避免创建临时对象,并减少了额外的赋值操作,提高了代码的执行效率。

  2. const成员变量的初始化:当类中有const修饰的成员变量时,只能使用初始化列表来进行初始化,因为const成员变量一旦被创建就不能再次赋值。

  3. 引用成员变量的初始化:引用成员变量必须在定义时进行初始化,并且只能通过初始化列表进行初始化。

  4. 基类和成员对象的初始化顺序:使用初始化列表可以指定基类和成员对象的初始化顺序,确保正确的初始化顺序。这对于继承或包含其他类的情况非常重要。

  5. 数组成员变量的初始化:如果类中包含数组成员变量,那么只能使用初始化列表来进行初始化。

  6. 更灵活的初始化选项:使用初始化列表,可以为成员变量提供不同的初始化选项,例如调用其他构造函数或者传递参数。

基本格式: 


类对象作为类成员 

例如:

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

示例中,我

们定义了一个Phone类来表示手机,它具有一个字符串类型的品牌成员和一个display()函数来显示手机的品牌。

然后,我们定义了一个Student类,它具有一个名为phone的成员,类型为Phone,表示学生的手机。在Student的构造函数中,我们使用初始化列表phone(phoneBrand)为phone成员变量初始化一个Phone对象。

display()函数中,我们首先显示学生的姓名,然后调用phone对象的display()函数显示手机的品牌。

#include <iostream>
#include <string>

using namespace std;

class Phone 
{
public:
    Phone(const string& brand) : brand(brand) {}
    void display() 
    {
        cout << "Brand: " << brand << endl;
    }
private:
    string brand;
};

class Student 
{
public:
    Student(const string& name, const string& phoneBrand)
        : name(name), phone(phoneBrand) {}  // 初始化列表中使用Phone的构造函数
    void display() 
    {
        cout << "Name: " << name << endl;
        cout << "Phone: ";
        phone.display();
    }
private:
    string name;
    Phone phone;  // 使用Phone对象作为类成员
};

int main() 
{
    Student student("John", "Apple");
    student.display();

    return 0;
}

注意:当其他类对象作为本类成员,构造时候先构造类对象,在构造自身,析构的顺序与构造相反。 


静态成员

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员

静态成员变量

  • 所有对象共享同一份数据
  • 在编译阶段分配内存
  • 类内声明,类外初始化

格式 

class ClassName 
{
public:
    static dataType variableName; // 静态成员变量的声明
};

dataType ClassName::variableName = initialValue; // 静态成员变量的定义和初始化

两种访问方式 

静态成员函数

  • 所有对象共享同一个函数
  • 静态成员函数只能访问静态成员变量 

 格式:

class ClassName 
{
public:
    static returnType functionName(parameters); // 静态成员函数的声明
};

returnType ClassName::functionName(parameters) 
{
    // 函数实现
    // 可以直接访问静态成员变量和调用其他静态成员函数
}

注意:

静态成员函数只能访问静态成员变量的原因是因为静态成员函数不依赖于类的对象,它们可以在没有创建类的对象的情况下被调用。由于没有对象,静态成员函数无法访问属于对象的非静态成员变量,因为这些变量是与具体的对象实例绑定在一起的。静态成员变量属于整个类,不依赖于任何对象,因此静态成员函数可以直接访问它们。

如:

#include <iostream>

using namespace std;

class MyClass 
{
public:
    static int staticVar; // 静态成员变量

    static void staticFunction() 
{
        staticVar = 100; // 可以访问静态成员变量并修改其值
        cout << "Static Variable: " << staticVar << endl;
    }
};

int MyClass::staticVar = 0; // 静态成员变量的定义和初始化

int main() 
{
    MyClass::staticFunction(); // 通过类名调用静态成员函数

    return 0;
}

类外访问不到私有的静态成员函数。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python range函数

Python中的range()函数是一个强大的工具&#xff0c;用于生成一系列的整数。它在循环、迭代和序列生成等方面都有广泛的应用。本文将深入探讨range()函数的用法&#xff0c;提供详细的示例代码&#xff0c;并讨论其在Python编程中的实际应用。 什么是range()函数&#xff1f; …

springboot导出数据到excel模板,使用hutool导出数据到指定excel,java写入数据到excel模板

最近遇到一个需求&#xff0c;需要从数据库查询数据&#xff0c;写入到对应的excel导入模板中。再把导出的数据进行修改&#xff0c;上传。 我们项目用的是easyExcel&#xff0c;一顿百度搜索&#xff0c;不得其法。 主要是要把数据填充到指定单元格中&#xff0c;跟平时用到的…

计算机网络实验二:Packet Tracer的简单使用

目录 实验二&#xff1a;Packet Tracer的简单使用 2.1 实验目的 2.2 实验步骤 2.2.1 构建网络拓扑 2.2.2 配置各网络设备 2.2.3 网络功能验证测试 2.3 实验总结 实验二&#xff1a;Packet Tracer的简单使用 2.1 实验目的 ①练习packet tracer仿真软件的安装&#xff1…

mc我的世界服务器多少钱一个月?

我的世界服务器多少钱一个月&#xff1f;低至7元一个月&#xff0c;阿里云和腾讯云均可以选择mc服务器&#xff0c;阿里云2核2G3M轻量服务器87元一年、腾讯云轻量2核2G3M服务器88元一年&#xff0c;阿里云ECS云服务器2核2G3M带宽99元一年&#xff0c;腾讯云2核4G5M带宽轻量应用…

活动回顾丨云原生技术实践营上海站「云原生 AI 大数据」专场(附 PPT)

AI 势不可挡&#xff0c;“智算”赋能未来。2024 年 1 月 5 日&#xff0c;云原生技术实践营「云原生 AI &大数据」专场在上海落幕。活动聚焦容器、可观测、微服务产品技术领域&#xff0c;以云原生 AI 工程化落地为主要方向&#xff0c;希望帮助企业和开发者更快、更高效地…

菜鸡后端的前端学习记录

前言 记录一下看视频学习前端的的一些笔记&#xff0c;以前对Html、Js、CSS有一定的基础&#xff08;都认得&#xff0c;没用过&#xff09;&#xff0c;现在不想从头再来了&#xff0c;学学Vue框架&#xff0c;不定时更新&#xff0c;指不定什么时候就鸽了。。。。 Vue2 01…

初识汇编指令

1. ARM汇编指令 目的 认识汇编, 从而更好的进行C语言编程 RAM指令格式: 了解 4字节宽度 地址4字节对齐 方便寻址 1.1 指令码组成部分 : condition: 高4bit[31:28] 条件码 0-15 &#xff08;16个值 &#xff09; 条件码: 用于指令的 条件执行 , ARM指定绝大部分 都可…

Linux之快速入门(CentOS 7)

文章目录 一、Linux目录结构二、常用命令2.1 切换用户2.2查看ip地址2.3 cd2.4 目录查看2.5 查看文件内容2.6 创建目录及文件2.7 复制和移动2.82.93.0 一、Linux目录结构 目录作用/bin是 Binaries (二进制文件) 的缩写,这个目录存放着最经常使用的命令/dev是 Device(设备) 的缩写…

【GitHub项目推荐--不错的Rust开源项目】【转载】

01 Rust 即时模式 GUI 库 egui 是一个简单、快速且高度可移植的 Rust 即时模式 GUI 库&#xff0c;可以轻松地将其集成到你选择的游戏引擎中&#xff0c;旨在成为最易于使用的 Rust GUI 库&#xff0c;以及在 Rust 中制作 Web 应用程序的最简单方法。 项目地址&#xff1a;ht…

go 依赖注入设计与实现

在现代的 web 框架里面&#xff0c;基本都有实现了依赖注入的功能&#xff0c;可以让我们很方便地对应用的依赖进行管理&#xff0c;同时免去在各个地方 new 对象的麻烦。比如 Laravel 里面的 Application&#xff0c;又或者 Java 的 Spring 框架也自带依赖注入功能。 今天我们…

【ASOC全解析(一)】ASOC架构简介和欲解决的问题

【ASOC全解析&#xff08;一&#xff09;】ASOC架构简介和欲解决的问题 一、什么是ASOC以及ASOC解决的三个问题二、ASOC的组成与功能解决第一个问题解决第二个问题解决第三个问题 三、ASOC基本工作原理 /********************************************************************…

Parade Series - Android Studio

硬件支持 CPU i7 RAM 16Gb -------------- ------- Java 3Gb Android 33GbJava Enviroment C:\ ├─ Java │ ├─ jdk1.8.0_181 │ ├─ jre1.8.0_181 │ ├─ maven-3.8.5 │ └─ gradle-6.5 └─ Cache├─ gr…

基于中文垃圾短信数据集的经典文本分类算法实现

垃圾短信的泛滥给人们的日常生活带来了严重干扰&#xff0c;其中诈骗短信更是威胁到人们的信息与财产安全。因此&#xff0c;研究如何构建一种自动拦截过滤垃圾短信的机制有较强的实际应用价值。本文基于中文垃圾短信数据集&#xff0c;分别对比了朴素贝叶斯、逻辑回归、随机森…

哈希--73. 矩阵置零/medium 理解度A

73. 矩阵置零 1、题目2、题目分析3、复杂度最优解代码示例4、适用场景 1、题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,…

Overleaf(LaTeX文档在线编写平台)使用学习记录

一、LaTeX简概[1] LaTeX&#xff0c;是一种基于TEX的排版系统&#xff0c;是一种可以处理排版和渲染的标记语言。由美国计算机科学家莱斯利兰伯特在20世纪80年代初期开发&#xff0c;利用这种格式系统的处理&#xff0c;即使用户没有排版和程序设计的知识也可以充分发挥由TEX所…

CACTER邮件安全网关独家安全解决方案——保障企业邮件系统安全

随着科技的不断发展&#xff0c;网络攻击技术也在不断演变&#xff0c;尤其是在电子邮件领域&#xff0c;各种高级变种威胁层出不穷&#xff0c;比如定制化的钓鱼邮件和带有高级恶意软件的邮件等。这些威胁邮件往往能够绕过传统的安全防护措施&#xff0c;包括反垃圾邮件、反钓…

软件安全测试的重要性简析,专业安全测试报告如何申请?

在当今数字化时代&#xff0c;软件在我们的日常生活中扮演着至关重要的角色&#xff0c;但也带来了各种潜在的安全威胁。为了保障用户的信息安全和维护软件的可靠性&#xff0c;软件安全测试显得尤为重要。 软件安全测试是指通过一系列的方法和技术&#xff0c;对软件系统中的…

pikachu_csrf通关攻略

csrf&#xff08;get&#xff09; 打开pikachu靶场&#xff1a; 1. 根据提示给的账户密码进行登录 2. 打开代理拦截数据包将拦截数据发送到已打开的burp中&#xff1a; 修改数据进行发包&#xff1a; 从上面的url可见&#xff0c;修改用户信息的时候&#xff0c;是不带任何不…

性能优化(CPU优化技术)-NEON指令介绍

「发表于知乎专栏《移动端算法优化》」 本文主要介绍了 NEON 指令相关的知识&#xff0c;首先通过讲解 arm 指令集的分类&#xff0c;NEON寄存器的类型&#xff0c;树立基本概念。然后进一步梳理了 NEON 汇编以及 intrinsics 指令的格式。最后结合指令的分类&#xff0c;使用例…

如何基于 ESP32 芯片测试 WiFi 连接距离、获取连接的 AP 信号强度(RSSI)以及 WiFi吞吐测试

测试说明&#xff1a; 测试 WiFi 连接距离&#xff0c;是将 ESP32 作为 WiFi Station 模式来连接路由器&#xff0c;通过在开阔环境下进行拉距来测试。另外&#xff0c;可以通过增大 WiFi TX Power 来增大连接距离。 获取连接的 AP 信号强度&#xff0c;一般可以通过 WiFi 扫描…