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() 
{// 创建对象1MyClass 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;
}

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

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

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

相关文章

【前端web入门第一天】01 开发环境、HTML基本语法文本标签

文章目录: 1. 准备开发环境 1.1 vs Code基本使用 2.HTML文本标签 2.1 标签语法2.2 HTML基本骨架2.3 标签的关系2.4 注释2.5 标题标签2.6 段落标签2.7 换行与水平线标签2.8 文本格式化标签 1. 准备开发环境 VSCode与谷歌浏览器离线版,安装包评论区自提. VSCode默认安装位置:C…

离线编译 onnxruntime-with-tensortRT

记录为centos7的4090开发机离线编译onnxruntime的过程&#xff0c;因为在离线的环境&#xff0c;所以踩了很多坑。 https://onnxruntime.ai/docs/execution-providers/TensorRT-ExecutionProvider.html 这里根据官网的推荐安装1.15 版本的onnx 因为离线环境&#xff0c;所以很…

微信小程序如何做到高效引流?-数灵通

随着微信小程序制作门槛的降低&#xff0c;大量的小程序如雨后春笋般涌现&#xff0c;其中小程序商城类型尤为众多。然而&#xff0c;由于微信自身的流量有限&#xff0c;对于大多数小程序商城而言&#xff0c;获取足够的流量成为了一大挑战。 针对这一问题&#xff0c;我们可以…

【Python编程工具】【ssh连接Docker容器】如何使用Docker容器里的python环境,如何调试在容器中的代码

文章目录 方案一览Gateway软件介绍启动容器配置apt源在容器中安装SSH服务器配置SSH服务器生成SSH密钥启动SSH服务为root创建密码连接到容器使用Gateway 方案一览 本篇博客将介绍如何在Docker容器中打开SSH连接服务&#xff0c;以及如何使用JetBrains Gateway软件进行代码调试。…

C++ | 六、栈 Stack、队列 Queue

栈的基础知识 栈&#xff08;stack&#xff09;是一种数据结构&#xff0c;在C中属于STL&#xff08;标准库&#xff09;特点&#xff1a;先进后出 栈的使用&#xff1a; 一、引入头文件<stack>二、创建栈变量&#xff08;类似容器、集合的创建方式&#xff09;&#xf…

GNSS模块引领共享出行新纪元:创新微公司的技术创新之路

共享出行服务正在成为城市交通中不可或缺的一环&#xff0c;而全球导航卫星系统&#xff08;GNSS&#xff09;模块的应用为这一领域注入了新的活力。创新微公司通过其先进的GNSS技术&#xff0c;为共享出行服务提供了更智能、高效的解决方案。本文将探讨创新微公司的GNSS模块在…

java(渣哇)------输入与输出语句(详解) (๑•̌.•๑)

目录 一.java的输出语句&#xff1a; System.out.println() -----输出并换行 System.out.print() -----输出但不换行 System.out.printf() -----类似C语言的printf()输出语句,按格式进行输出 二.java的输入语句&#xff1a; 2.1-----Scanner的基础用法&#xff1a; 2.2…

bash 5.2中文修订4

Compound Commands 复合命令 复合命令是 shell 编程语言的结构。每个构造都以保留字或控制运算符开始&#xff0c;并以相应的保留字或运算符终止。与复合命令关联的任何重定向&#xff08;请参阅 Redirections &#xff09;都适用于该复合命令中的所有命令&#xff0c;除非显式…

AI-数学-高中-8-函数奇偶性

原作者视频&#xff1a;函数】6函数奇偶性&#xff08;易-中档&#xff09;_哔哩哔哩_bilibili 示例&#xff1a; 已知奇偶性求解析式&#xff1a; 奇偶、单调函数综合示例&#xff1a;

Redis的五种数据类型(string、hash 、list、set、zset)

Redis 提供了丰富的数据类型&#xff0c;常见的有五种&#xff1a;String&#xff08;字符串&#xff09;&#xff0c;Hash&#xff08;哈希&#xff09;&#xff0c;List&#xff08;列表&#xff09;&#xff0c;Set&#xff08;集合&#xff09;、Zset&#xff08;有序集合&…

云手机与实体手机的对比

在数字化时代&#xff0c;云手机作为一种虚拟手机在云端服务器上运行&#xff0c;与传统的实体手机相比存在诸多差异。让我们深入探讨云手机与实体手机之间的区别&#xff0c;以便更好地了解它们的特点和优势。 外观上的差异 实体手机具有实际的外观和重量&#xff0c;占据一定…

从0开始python算法工程师(一):安装conda

1.为什么要安装conda 主要是为了在命令行使用conda命令管理虚拟环境。 2.两种conda Windows用户&#xff0c;一般建议初学者都安装anaconda&#xff08;省事&#xff09;&#xff1b;Windows用户&#xff0c;熟练的安装者则安装miniconda&#xff08;省存储空间&#xff09;…