类和对象-对象特性

news2025/1/10 17:13:14

前言:

主要讲述对象的初始化与清理,构造函数与析构函数,其分类和调用,以及调用时机等相关内容

对象的初始化与清理:

1.生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用的时候也会删除一些自己的信息数据保证安全

2.C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置

构造函数和析构函数:

对象的初始化和清理也是两个非常重要的安全问题

一个对象或者变量没有初始状态,对其使用后果是未知

同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题

C++利用了构造函数和析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供编译器提供的构造函数和析构函数是空实现。

构造函数:

主要作用在于创建对象时为对象的成员属性赋值,构造函数有编译器自动调用,无需手动调用。

析构函数:

主要作用在于对象销毁前系统自动调用,执行一些清理工作。

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

  1. 构造函数,没有返回值也不写void

  1. 函数名称与类名相同

  1. 构造函数可以有参数,因此可以发生重载

  1. 程序在调用对象时候会自动调用构造,无需手动调用,而且指挥调用一次

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

  1. 析构函数,没有返回值也不写void

  1. 函数名称与类名相同,在名称前加上符号~

  1. 析构函数不可以有参数,因此不可以发生重载

4.程序在对象销毁前会自动调用析构,无需手动调用,而且指挥调用一次

详情请看以下代码:

#include <iostream>
using namespace std;
//对象的初始化和清理
//1.构造函数 进行初始化操作
class Person
{
public:
    //1.构造函数
    //没有返回值 不用写void
    //函数名 与类名相同
    //构造函数可以有参数,可以发生重载
    //创建对象的时候,构造函数会自动调用,而且只调用一次
    Person()
    {
        cout << "Person 构造函数的调用" << endl;//编译器自己也会写,只不过是空的
    }
    //2.析构函数 进行清理的操作
    //没有返回值 不写void
    //函数名和类名相同 在名称前加~
    //析构函数不可以有参数的,不可以发生重载
    //对象在销毁前,析构函数会自动调用,而且只调用一次
    ~Person()
    {
        cout << "Person 的析构函数调用" << endl;
    }
};
//构造和析构都是必须有的实现,如果我们自己不提供,编译器会提供一个空实现的构造和析构
void test01()
{
    Person p;//在栈上的数据,test01执行完毕后,释放这个对象
}
int main()
{
    test01();
    Person p;
    system("pause");
    return 0;
}

构造函数的分类及调用

两种分类方式:

按参数分为:有参构造和无参构造

按类型分为;普通构造和拷贝构造

三种调用方式:

括号法

显示法

隐式转换法

以下代码可以让你清楚的了解构造函数的分类方式和调用方式

#include <iostream>
using namespace std;
//1.构造函数的分类及调用
//分类
//按照参数分类  无参构造(默认构造)和有参构造
//按照类型分类  普通构造和拷贝构造
class Person
{
public:
    //构造函数
    Person()
    {
        cout << "Person的无参构造函数调用" << endl;
    }
    Person(int a)
    {
        age = a;
        cout << "Person的有参构造函数调用" << endl;
    }
    //拷贝构造
    Person(const Person &p)
    {
        //将传入的人身上的所有属性,拷贝到我身上
        age = p.age;
        
    }
    ~Person()
    {
        cout << "Person的析构函数调用" << endl;
    }
    int age;
};
//调用
void test01()
{
    //1.括号法
    //Person p1;//默认构造函数的调用
    //Person p2(10);//有参构造
    //Person p3(p2);//拷贝构造函数
    注意事项1:
    调用默认构造函数的时候,不要加()
    因为下面这段代码,编译器会认为是一个函数的声明
    Person p1();
    //cout << "p2的年龄" << p2.age << endl;
    //cout << "p3的年龄" << p3.age << endl;
    //2.显示法
    Person p1;
    Person p2 = Person(10);//有参构造
    Person p3 = Person(p2);//拷贝构造
    Person(10);//匿名对象    特点: 当前行执行结束后,系统会立即回收匿名对象
    /*注意事项2:
    不要利用拷贝构造函数 初始匿名对象*/
    Person(p3);//有问题!!!
    //编译器会认为Person(p3)==Person p3;对象的声明
    //3.隐式转换法
    Person p4 = 10;//相当于 Person p4 = Person(10);
    Person p5 = p4;//拷贝构造
}

int main()
{
    test01();
    system("pause");
    return 0;
}

拷贝构造函数调用时机:

C++中拷贝函数调用时机通常有三种情况:

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

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

  1. 以值方式返回局部变量

#include <iostream>
using namespace std;
//拷贝构造函数调用时机:
//1.使用一个已经创建完毕的对象来初始化一个新的对象
// 
//2.值传递的方式给函数参数传值
// 
//3.以值方式返回局部变量

class Person
{
public:
    Person()
    {
        cout << "Person默认构造函数调用" << endl;
    }
    Person(int age)
    {
        cout << "Person有参构造函数调用" << endl;
        m_Age = age;
    }
    Person(const Person& p)
    {
        cout << "Person拷贝构造函数的调用" << endl;
        m_Age = p.m_Age;
    }
    int m_Age;
};
void test01()
{
    Person p1(20);
    Person p2(p1);
    cout << "p2的年龄" << p2.m_Age << endl;
}

void doWork(Person p)
{
    ;
}
void test02()
{
    Person p;
    doWork(p);
}

Person doWork2()
{
    Person p1;
    cout << (int*)&p1 << endl;
    return p1;

}
void test03()
{
    Person p = doWork2();
}
int main()
{
    test01();
    system("pause");
    return 0;
}

构造函数调用规则:

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

  1. 默认构造函数(无参,函数体为空)

  1. 默认析构函数(无参,函数体为空)

  1. 默认拷贝构造函数,对属性进行拷贝

构造函数调用规则如下:

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

  1. 如果用户定义拷贝构造函数,C++不会再提供其他构造函数

#include <iostream>
using namespace std;
//默认情况下, C++编译器至少给一个类添加3个函数
//1.默认构造函数(无参,函数体为空)
//2.默认析构函数(无参,函数体为空)
//3.默认拷贝构造函数,对属性进行拷贝(值拷贝)
//
//构造函数调用规则如下:
//1.如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造
//2.如果用户定义拷贝构造函数,C++不会再提供其他构造函数

class Person
{
public:
    Person()
    {
        cout << "Person的默认构造函数调用 " << endl;
    }
    ~Person()
    {
        cout << "Person的默认析构函数调用" << endl;
    }
    Person(const Person &p)
    {
        cout << "Person的拷贝构造函数调用" << endl;
    }
    int m_Age;
};

void test01()
{
    Person p;
    p.m_Age = 18;
    Person p2(p);
    cout << "p2的年龄为:" << p2.m_Age << endl;
}
int main()
{
    test01();
    system("pause");
    return 0;
}

深拷贝与浅拷贝:

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

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

#include <iostream>
using namespace std;
//深拷贝与浅拷贝
class Person
{
public:
    Person()
    {
        cout << "Person的默认构造函数调用" << endl;
    }
    Person(int age,int height)
    {
        m_Age = age;
        m_Height = new int(height);
        cout << "Person的有参构造函数调用" << endl;
    } 
    ~Person()
    {
        //析构代码,将堆区开辟数据做释放操作
        if (m_Height != NULL)
        {
            delete m_Height;
            m_Height = NULL;
        }
        cout << "Person的析构函数调用" << endl;
    }
    //自己实现拷贝构造函数,解决浅拷贝带来的问题
    Person(const Person& p)
    {
        cout << "Person拷贝构造函数的调用" << endl;
        m_Age = p.m_Age;
        //m_Height = p.m_Height//编译器默认实现就是这行代码
        //深拷贝操作
        m_Height = new int(*p.m_Height);
    }
    int m_Age;
    int* m_Height;
};
void test01()
{
    Person p1(18,160);
    cout << "p1的年龄为:" << p1.m_Age << endl;

    Person p2(p1);    
    cout << "p2的年龄为:" << p2.m_Age << endl;


}
int main()
{
    test01();
    system("pause");
    return 0;
}

初始化列表:

作用:

C++提供了初始化列表的语法,用来初始化属性

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

#include <iostream>
using namespace std;
//初始化列表
class Person
{
public:

    //传统初始化操作
    //Person(int a, int b, int c)
    //{
    //    m_A = a;
    //    m_B = b;
    //    m_C = c;
    //}
    //初始化列表初始化属性
    Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c)
    {

    }

    int m_A;
    int m_B;
    int m_C;
};

void test01()
{
    Person p(30,20,10); 
    //Person p(10,20,30);
    cout << "m_A = " << p.m_A << endl;
    cout << "m_B = " << p.m_B << endl;
    cout << "m_C = " << p.m_C << endl;

}
int main()
{
    test01();
    system("pause");
    return 0;
}

类对象作为类成员:

该成C++类中的成员可以是另一个类的对象,我们称员为对象成员

比如:

class A{ }
class B
{
A_a;
}

B类中有对象A,A为对象成员

构造的顺序:
当其他的类对象作为本类成员,构造时候先构造类对象,再构造本身
析构的顺序:
与构造的顺序想法,先析构本身,再析构类对象
#include <iostream>
#include <string>
using namespace std;

//类对象作为类成员
class Phone
{
public:
    Phone(string pName)
    {
        m_PName = pName;
    }
    //手机品牌名
    string m_PName;
};
class Person
{
public:
    Person(string name, string pName) :m_Name(name), m_Phone(pName)
    {

    }
    //姓名
    string m_Name;
    //手机
    Phone m_Phone;
};
void test01()
{
    Person p("张三", "三星");
    cout << p.m_Name << "拿着" << p.m_Phone.m_PName << endl;
}
int main()
{
    test01();
    system("pause");
    return 0;
}

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

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

相关文章

Java基础多线程下篇

本篇本文目录:一.线程死锁1.重入锁2.释放锁3.死锁4.wait和notify二.锁1.ReentrantLock2.Condition3.ReadWriteLock4.StampedLock5.Semaphore6.线程并发安全(1) concurrent(2) atomic三.线程池1.通过线程池分配线程2.FixedThreadPool3.CachedThreadPool4.ScheduledThreadPool四.…

粒子输运的蒙特卡罗方法介绍

蒙特卡罗大部分改概念和方法不依赖空间的维度&#xff0c;可以先讨论一维情况下粒子的蒙特卡罗输运。单能粒子输运的玻尔兹曼方程可以写为&#xff1a;仅考虑散射和吸收EtEsEa吸收意味着粒子生命周期的终结。图2.1示例&#xff1a;通过蒙特卡罗方法确定目标几何体内外的中子分布…

宕机了,Redis 如何避免数据丢失?

前言 如果有人问你&#xff1a;"你会把 Redis 用在什么业务场景下&#xff1f;" 我想你大概率会说&#xff1a;"我会把它当作缓存使用&#xff0c;因为它把后端数据库中的数据存储在内存中&#xff0c;然后直接从内存中读取数据&#xff0c;响应速度会非常快。…

机器学习实战(第二版)读书笔记(5)——Embedding

一、使用范围(作者经验)&#xff1a; 类别 < 10 通常采用独热编码方式。类别 > 50( 通常这种情况需要使用哈希桶)&#xff0c;通常最好使用嵌入。10 - 50 可以尝试两种方式&#xff0c;选择最优。 目的&#xff1a;同义词具有非常接近的嵌入&#xff08;将嵌入向量当作嵌…

股票接口自动下单怎么处理?

股票接口自动下单怎么处理的&#xff1f;经过小编的小编的了解&#xff0c;股票交易接口是由很多资源和开发源码的设计来构建的&#xff0c;有的专业开发团队将这些开发研究和完善&#xff0c;但是&#xff0c;这些股票接口不一定就是由其自身提供的&#xff0c;可以是投资者个…

C语言基础(一)—— C语言概述(领域、编译过程、IDE)

1. 什么是C语言语言是人和人交流&#xff0c;C语言就是人和计算机交流的一种语言2. 为什么要学习C语言2.1 C语言特点优点&#xff1a;代码量小执行速度快功能强大编程自由缺点&#xff1a;写代码实现周期长可移植性较差过于自由&#xff0c;经验不足易出错对平台库依赖较多2.2 …

Hystrix执行时内部原理

Hystrix最基本的支持高可用的技术资源隔离和限流。创建command,执行这个command,配置这个command对应的group和线程池。这里分析一下开始执行这个command,调用了这个command的execute()方法之后,Hystrix底层的执行流程和步骤以及原理是什么。整个8大步骤的流程图: 步骤一:…

Hive(6):数据定义语言(DDL)案例

1 原生数据类型案例 文件archer.txt中记录了相关信息&#xff0c;内容如下所示&#xff0c;其中字段之间分隔符为制表符\t,要求在Hive中建表映射成功该文件。 1 后羿 5986 1784 396 336 remotely archer 2 马可波罗 5584 200 362 344 remotely archer 3 鲁班七号 5989 1756 4…

JVM笔记(5)—— 运行时数据区—— 方法区

上一篇&#xff1a;JVM笔记&#xff08;4&#xff09;—— 运行时数据区——堆空间 一、栈、堆、方法区的交互关系 进程运行过程中&#xff0c;在方法中创建对象时通过方法区中的类型信息在堆中创建对应的对象&#xff0c;对象中又存有指向方法区中对应类型信息的指针&#xf…

Python采集热搜评论数据,制作词云分析,又是吃瓜的一天

前言 最近微博上的爆的热搜是不少啊&#xff0c;咳咳&#xff0c;23年1月31号记汪峰旷工一次 之前有营销号预言23年的娃瓜 已经爆出来一个了 好像是说还有两个来着 也不知道是谁的娃~ 现在已经没有什么可以震惊到我的了 胡歌都有娃了 彭于晏抓紧吧 有点点的无聊 就来用Pytho…

MySQL事件

文章目录事件介绍事件调度查询事件调度状态开关事件调度(临时)开关事件调度(永久)事件使用创建事件语法子句分析执行计划子句事件主体子句查询事件修改事件删除事件事件介绍 MySQL事件(event)是根据指定时间表执行的任务&#xff0c;称为计划事件。事件包含一个或多个SQL语句的…

【刷题】二进制求和

当你觉得小学二年级教的的竖式学会了以后&#xff0c;此题又是一记重击。 目录 前言 一、题目 二、找规律 三、思想 1.位数相同 2.位数不同 3.注意事项 四、具体实现 总结 前言 同上次做过的的二进制求和相似&#xff08;按位异或求出的是无进位和&#xff0c;按位与求…

大数据技术架构(组件)14——Hive:掩码函数杂项函数

1.4.8、掩码函数1.4.8.1、mask-->Hive2.1.01.4.8.12、mask_first_n->Hive2.1.01.4.8.13、mask_last_n -->Hive2.1.01.4.8.14、mask_show_first_n-->Hive2.1.01.4.8.15、mask_show_last_n -->Hive2.1.01.4.8.16、mask_hash -->Hive2.1.0支持版本返回值类型函数…

让你深夜emo的“网抑云”,是如何做产品设计的?

网易云音乐作为国内首个以“歌单”为核心架构的音乐APP&#xff0c;有的人喜欢它的热评&#xff0c;有的人却觉得它的版权太少&#xff0c;虽然网易云音乐不是曲库最丰富的听歌软件&#xff0c;但绝对是听歌软件里情感体验最好的。 我很好奇它具有什么力量&#xff0c;能够使用…

ReentrantReadWriteLock可重入读写锁

目录 读写锁&#xff1a; 锁降级 锁饥饿&#xff1a; 读写锁&#xff1a; 定义&#xff1a;一个资源能够被多个读线程访问&#xff0c;或者被一个写线程访问&#xff0c;但是不能同时存在读写线程。 特点:读写互斥&#xff0c;写锁独占&#xff0c;读读可共享,读没有完…

分布式学习第三天—远程调用和网关

Feign远程调用 Feign的介绍 Feign是一个声明式的http客户端&#xff0c;官方地址&#xff1a;https://github.com/OpenFeign/feign 其作用就是帮助我们优雅的实现http请求的发送 Feign远程调用的使用步骤 1.引入依赖 在子模型服务的pom文件中引入feign的依赖&#xff1a; &l…

【计网】入门知识

一些基本认识网络传输基本要素&#xff1a;网络编程&#xff1a;python的网络编程方式TCP和UDP一些编程技巧socket实现TCP通信网络传输基本要素&#xff1a; 有连接通道、传输字节数据、输入输出遵守一样的协议 网络编程&#xff1a; CS&#xff08;QQ下载客户端&#xff09…

linux防火墙究竟如何使用?iptables的原理与简单应用

1. 什么是防火墙&#xff1f; 在计算机体系中&#xff0c;防火墙是基于预定安全规则来监视和控制传入和传出网络流量的网络安全系统。该计算机流入流出的所有网络通信均要经过此防火墙。防火墙对流经它的网络通信进行扫描&#xff0c;这样能够过滤掉一些攻击&#xff0c;以免其…

Vulkan 理解Vertex Input Description

此文为个人记录&#xff0c;感兴趣直接看https://zhuanlan.zhihu.com/p/450157594 首先&#xff0c;一个顶点的结构体 struct Vertex {glm::vec3 pos;glm::vec3 color; }CPU端给出顶点数据 const std::vector<Vertex> vertices {{{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}},…