[C++核心编程](四):类和对象——对象特性

news/2024/4/15 17:05:26

目录

对象的初始化和清理

构造函数和析构函数

构造函数

    构造函数的分类和调用

    拷贝构造函数的调用时机

    构造函数的调用规则

   深拷贝和浅拷贝*

  初始化列表

  类对象作为类成员

  静态成员(static)

析构函数

对象模型和this指针

this指针

空指针访问成员函数

const修饰成员函数


对象的初始化和清理

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

构造函数和析构函数

  • 编译器自动调用,完成对象初始化和清理工作
  • 如果程序员不自行实现,编译器提供的都是空实现

构造函数

     作用:创建对象时为对象的成员属性赋值,编译器自动调用,无须手动调用

     语法: 类名 () {}

  1. 没有返回值,也不用写void
  2. 函数名称与类名相同
  3. 可有参数,可重载
  4. 自动调用,无须手动调用且只调用一次
    构造函数的分类和调用

        分类:有参构造和无参构造(按参数)、普通构造和拷贝构造(按类型)

        调用方法:括号法、显示法、隐式转换法

        匿名对象:执行结束后,立即释放该对象。

        注意:

        1.创建对象时调用默认构造函数的时候不要加(),编译器认为是一个函数声明;

        2.不要使用拷贝构造函数初始化匿名对象,编译器认为是一个对象声明;

    拷贝构造函数的调用时机

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

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

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

#include <iostream>
using namespace std;class Cube
{
public:int m_L;Cube(){cout << "Cube 无参默认构造函数 调用" << endl;}Cube(int a){m_L = a;cout << "Cube 有参构造函数 调用" << endl;}Cube(const Cube &p){m_L = p.m_L;cout << "Cube 拷贝构造函数 调用" << endl;}~Cube(){cout << "Cube 析构函数 调用" << endl;}
};//使用创建完毕的对象初始化一个新对象
void test01()
{Cube p1(20);Cube p2(p1); cout << "p2 m_L value:" << p2.m_L << endl;}//值传递的方式给函数参数传值
void dowork1(Cube p)
{cout << "p m_L value:" << p.m_L << endl;
}void test02()
{Cube s1(30);dowork1(s1);
}//以值方式返回局部对象
Cube dowork2(void)
{Cube m1(40);cout << (int*)&m1 << endl;return m1;
}void test03()
{Cube m = dowork2();cout << (int*)&m << endl;cout << "m m_L value:" << m.m_L << endl;
}int main(void)
{test01();test02();test03();system("pause");return 0;
}
    构造函数的调用规则

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

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

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

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

        调用规则:

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

        2.如果用户定义拷贝构造函数,c++不再提供其它构造函数

   深拷贝和浅拷贝*

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

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

#include <iostream>using namespace std;class Cube
{
public:int m_L;int* p_H;Cube(){cout << "Cube 无参默认构造函数 调用" << endl;}Cube(int a, int Hight){m_L = a;p_H = new int(Hight);cout << "Cube 有参构造函数 调用" << endl;}//自行实现拷贝构造函数,解决浅拷贝的问题Cube(const Cube& p){m_L = p.m_L;p_H = new int(*p.p_H); //深拷贝}~Cube(){if (p_H != NULL){delete p_H;p_H = NULL;}cout << "Cube 析构函数 调用" << endl;}
};//浅拷贝,问题:堆区的内存重复释放,使用深拷贝解决
void test01()
{Cube p1(20, 40);cout << "p1 m_L and p_H value:" << p1.m_L << "," << *p1.p_H << endl;Cube p2(p1); cout << "p2 m_L and p_H value:" << p2.m_L << "," << *p2.p_H << endl;
}int main(void)
{test01();system("pause");return 0;
}
  初始化列表

        作用:用于初始化属性

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

#include <iostream>using namespace std;class Cube
{
public:int m_L;int m_H;//初始化列表初始化属性Cube(int a, int b) :m_L(a), m_H(b){}
};int main(void)
{Cube p1(10, 20);cout << "p1 m_L and p_H value:" << p1.m_L << "," << p1.m_H << endl;system("pause");return 0;
}
  类对象作为类成员

        c++类中的成员可以是另一个类的对象;

        注意:先构造类对象,再构造自身;析构与构造相反。

#include <iostream>
#include <string>using namespace std;class Phone
{
public:string m_phname;Phone(string pname){m_phname = pname;cout << "Phone 构造函数调用" << endl;}~Phone(){cout << "Phone 析构函数调用" << endl;}
};class Person
{
public:string m_name;Phone m_phone;//初始化列表初始化属性Person(string name, string phname) :m_name(name), m_phone(phname){cout << "Person 构造函数调用" << endl;}~Person(){cout << "Person 析构函数调用" << endl;}
};void test()
{Person p1("zhangsan", "HUAWEI");cout << p1.m_name << "拿着" << p1.m_phone.m_phname << "手机!" << endl;
}int main(void)
{test();system("pause");return 0;
}
  静态成员(static)
  • 静态成员变量

        1.所有对象共享同一份数据

        2.在编译阶段分配内存

        3.类内声明,类外初始化

  • 静态成员函数

        1.所有对象共享同一个函数

        2.静态成员函数只能访问静态成员变量

#include <iostream>
#include <string>using namespace std;class Person
{
public:int m_B;static int phone_number;static void func(){phone_number = 900;cout << "static void func()调用" << endl;}
private:static int number;  //也可以访问static void func2(){phone_number = 900;cout << "static void func2()调用" << endl;}
};int Person::phone_number = 123;
int Person::number = 123;void test()
{Person p1;p1.phone_number = 100;p1.func();cout << "p1.phone_number:" << p1.phone_number << endl;Person p2;p2.phone_number = 200;cout << "p1.phone_number:" << p1.phone_number << endl;cout << "p1.phone_number:" << p2.phone_number << endl;Person::func();//Person::func2(); //私有的无法访问cout << "phone_number:" << Person::phone_number << endl; //通过类名访问//cout << "phone_number:" << Person::number << endl; //私有的无法访问
}int main(void)
{test();system("pause");return 0;
}

析构函数

      作用:对象销毁前系统自动调用,执行一些清理工作

      语法: ~类名() {}

  1. 没有返回值,也不用写void
  2. 函数名称与类名相同,在名称前加上符号~
  3. 无参数,无法重载
  4. 自动调用,无须手动调用且只调用一次
#include <iostream>using namespace std;class Cube
{
public:int m_L;Cube(){cout << "Cube 无参默认构造函数 调用" << endl;}Cube(int a){m_L = a;cout << "Cube 有参构造函数 调用" << endl;}//拷贝构造函数Cube(const Cube &p){m_L = p.m_L;cout << "Cube 拷贝构造函数 调用" << endl;}~Cube(){cout << "Cube 析构函数 调用" << endl;}
};void test01()
{//括号法Cube p1;      //无参Cube p2(20);  //有参Cube p3(p2);  //拷贝cout << "p2 m_L:" << p2.m_L << endl;cout << "p3 m_L:" << p3.m_L << endl;//显示法Cube s1;Cube s2 = Cube(10);Cube s3 = Cube(s2);//Cube(10);  //匿名对象,特点:当前行执行结束后,立即释放该对象。cout << "s2 m_L:" << s2.m_L << endl;cout << "s3 m_L:" << s3.m_L << endl;//Cube(s3); 相当于 Cube s3;  不要使用拷贝构造函数初始化匿名对象//隐式转换法Cube s4 = 15;Cube s5 = s4;cout << "s4 m_L:" << s4.m_L << endl;cout << "s5 m_L:" << s5.m_L << endl;
}int main(void)
{test01();system("pause");return 0;
}

对象模型和this指针

        成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上

#include <iostream>
#include <string>using namespace std;class Person
{int m_A; //非静态成员变量,属于类的对象上static int m_B; //静态成员变量,不属于类的对象上void func() //非静态成员函数,不属于类的对象上{}static void func1() //静态成员函数,不属于类的对象上{}
};void test()
{Person p;//空对象占用内存空间为:1,为了区分多个空对象占内存的位置,每个空对象的内存都是唯一的;cout << "size of p = " << sizeof(p) << endl;
}void test02()
{Person p;cout << "size of p = " << sizeof(p) << endl;
}int main(void)
{test();test02();system("pause");return 0;
}

this指针

        this指针指向被调用的成员函数所属的对象

        1.隐含每一个非静态成员函数内的一种指针

        2.不需要定义,直接使用

        用途:

        1.当形参和成员变量同名时,可以使用this指针区分

        2.在类的非静态成员函数中返回对象本身,可以使用 return *this

#include <iostream>
#include <string>using namespace std;class Person
{
public:int age;Person(int age){//指向 被调用的成员函数 所属的对象this->age = age;}Person& PersonAddAge(Person p) //如果用值Person返回 ,会创建一个新的对象{this->age += p.age;return *this;}
};//1.解决名称冲突
void test()
{Person p1(10);cout << "p1 age = " << p1.age << endl;}void test1()
{Person p1(10);Person p2(10);//链式 编程思想p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);cout << "p2 age = " << p2.age << endl;}//2.返回对象本身用*thisint main(void)
{test();test1();system("pause");return 0;
}

空指针访问成员函数

        c++空指针可以访问成员函数,如果用到this指针要判断保证代码的健壮性

#include <iostream>
#include <string>using namespace std;class Person
{
public:int m_Age;void showClassName(){cout << "this is Person Class" << endl;}void showPersonAge(){if (this == NULL)return;cout << "age=" << m_Age << endl;}
};void test()
{Person* p = NULL;p->showClassName();p->showPersonAge();}int main(void)
{test();system("pause");return 0;
}

const修饰成员函数

常函数:

        1.成员函数后加const后成为常函数

        2.常函数内不可以修改成员属性       

        3.成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

        1.声明对象前加const称为常对象

        2.常对象只能调用常函数

#include <iostream>
#include <string>using namespace std;class Person
{
public:int m_Age;mutable int m_B; //mutable 常函数中也可以修改Person(int a, int b){m_Age = a;m_B = b;}//this指针的本质: 指针常量  指针的指向不可以修改 Person * const this;void showClassName(int b) const //修饰的this指针,相当于const Person * const this,让指针指向的值也不可以修改;{//this->m_Age = 100;  错误 无法修改this->m_B = b;}void func(){cout << "void func()" << endl;}
};void test()
{Person p(1,2);p.showClassName(50);cout << "m_Age:" << p.m_Age << "\tm_B:" << p.m_B << endl;const Person m(4,5); //m.m_Age = 10; 无法调用m.m_B = 30;m.showClassName(100);//常函数只能调用常函数//m.func();cout << "m_Age:" << m.m_Age << "\tm_B:" << m.m_B << endl;
}int main(void)
{test();system("pause");return 0;
}

推荐文章:[C++核心编程](四):类和对象——封装


http://www.mrgr.cn/p/77376072

相关文章

如何通过代理IP安全使用Linkedln领英?

LinkedIn是跨境外贸必备的拓客工具&#xff0c;世界各地的许多专业人士都使用领英来作为发布和共享内容的主要工具&#xff0c;这使得它成为跨境出海必备的渠道工具。 但是不少做外贸的朋友都知道&#xff0c;领英账号很容易遭遇限制封禁&#xff0c;但如果善用工具&#xff0…

华为配置WLAN高密业务示例

配置WLAN高密业务示例 组网图形 图1 配置高密WLAN环境网络部署组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 体育场由于需要接入用户数量很大&#xff0c;AP间部署距离较小&#xff0c;因此AP间的干扰较大&#xff0c;可能导致用户上网网…

Linux---进程信号

一、信号的概念 信号是一种向目标进程发送通知消息的机制 信号的特性(可以结合红绿灯、防空警报等生活样例来理解) 1、在信号没有出现之前&#xff0c;我们就已经知道如何去处理信号&#xff0c;即我们认识信号 2、信号是异步产生的&#xff0c;即我们不知道它具体何时产生 3、…

力扣● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

● 1049. 最后一块石头的重量 II 题目要把石头分成两堆&#xff0c;这两堆的重量差值最小。相撞之后剩下的石头重量就最小。其实就是要尽量把石头分为差不多重量的两堆&#xff0c;和昨天的● 416. 分割等和子集相似&#xff0c;这样就转换成了01背包问题。 和416题一样&…

【C++从0到王者】第四十六站:图的深度优先与广度优先

文章目录 一、图的遍历二、广度优先遍历1.思想2.算法实现3.六度好友 三、深度优先遍历1.思想2.代码实现 四、其他问题 一、图的遍历 对于图而言&#xff0c;我们的遍历一般是遍历顶点&#xff0c;而不是边&#xff0c;因为边的遍历是比较简单的&#xff0c;就是邻接矩阵或者邻接…

从 iOS 设备恢复数据的 20 个iOS 数据恢复工具

作为 iPhone、iPad 或 iPod 用户&#xff0c;您可能普遍担心自己可能会丢失存储在珍贵 iOS 设备中的所有宝贵数据。数据丢失的原因多种多样&#xff0c;这里列出了一些常见原因&#xff1a; 1. iOS 软件更新 2. 恢复出厂设置 3. 越狱 4. 误操作删除数据 5. iOS 设备崩溃 …

使用openai-whisper实现语音转文字

使用openai-whisper实现语音转文字 1 安装依赖 1.1 Windows下安装ffmpeg FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。 # ffmpeg官网 https://ffm…

WhatsApp代理設置指南

某些情況下&#xff0c;你可能需要使用WhatsApp代理來確保WhatsApp順暢且不受限制的通信。本篇文章將講解WhatsApp代理是什麼、WhatsApp代理的使用場景、以及如何在WhatsApp中使用和設置代理。​​​​​​​ WhatsApp代理指什麼? WhatsApp代理是位於可以訪問WhatsApp的國家或…

多输入多输出 | Matlab实现RIME-BP霜冰算法优化BP神经网络多输入多输出预测

多输入多输出 | Matlab实现RIME-BP霜冰算法优化BP神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现RIME-BP霜冰算法优化BP神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现RIME-BP霜冰算法优化BP神经网…

《汇编语言》- 读书笔记 - 第13章-int 指令

《汇编语言》- 读书笔记 - 第13章-int 指令 13.1 int 指令13.2 编写供应用程序调用的中断例程中断例程&#xff1a;求一 word 型数据的平方主程序中断处理程序执行效果 中断例程&#xff1a;将一个全是字母&#xff0c;以0结尾的字符串&#xff0c;转化为大写主程序中断处理程序…

【C++】C++的四种强制类型转换

1、C语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类型与接收返回值类型不一致时&#xff0c;就需要发生类型转化&#xff0c;C语言中总共有两种形式的类型转换&#xff1a;隐式类型转换…

mysql,for循环执行sql

遇到一个问题&#xff0c;我需要模拟上百万数据来优化sql&#xff0c;线上数据down不下来&#xff0c;测试库又没有&#xff0c;写代码执行要么慢要么就是sql语句太长。 于是&#xff0c;直接用mysql自带的功能去实现&#xff01; 简单而简单 mysql可以for循环&#xff1f;没…

Docker技术概论(4):Docker CLI 基本用法解析

Docker技术概论&#xff08;4&#xff09; Docker CLI 基本用法解析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:http…

Spring AI上架

Spring AI 来了 Spring AI 是 AI 工程师的一个应用框架,它提供了一个友好的 API 和开发 AI 应用的抽象,旨在简化 AI 应用的开发工序。 提供对常见模型的接入能力,目前已经上架 https://start.spring.io/,提供大家测试访问。(请注意虽然已经上架 start.spring.io,但目前还…

文件基础和文件fd

文章目录 预备知识C语言的文件接口系统调用文件fd 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站。 预备知识 我们平时说文件就是说文件里…

cyi青少年CTF擂台挑战赛 2024 #Round 1 wp

cyi青少年CTF擂台挑战赛 2024 #Round 1 wpWEB EasyMD5 靶机真不敢恭维 一个文件上传界面,得上传pdf传两个pdfhttps://www.cnblogs.com/wysngblogs/p/15905398.html 这篇文章看到md5碰撞,找到个工具fastcoll_v1.0.0.5 https://www.win.tue.nl/hashclash/后续写的wp,flag可能…

Gitlab Runner自动推送Docker映像

接上文,增加两个stage 最简单的推送,其实是在docker build后边带上--push的开关即可。 但是不经过测试就上传,Docker仓库里很快会堆满垃圾。 所以我们设计新增两个场景,经过测试之后才push映像去仓库。 stages:- build-docker-image- test- push-image variables:PAY_IMAGE…

黑马JavaWeb课程中安装vue脚手架出现的问题

1 安装node.js 要想前端工程化&#xff0c;必须安装node.js&#xff0c;前端工程化的环境。 在成功安装node.js后&#xff0c; 修改全局包安装路径为Node.js安装目录&#xff0c; 修改npm镜像源为淘宝镜像源&#xff0c;这里出现第一个问题&#xff0c;视频中给的淘宝镜像为&…

python实现常见一元随机变量的概率分布

一. 随机变量 随机变量是一个从样本空间 Ω \Omega Ω到实数空间 R R R的函数&#xff0c;比如随机变量 X X X可以表示投骰子的点数。随机变量一般可以分为两类&#xff1a; 离散型随机变量&#xff1a;随机变量的取值为有限个。连续型随机变量&#xff1a;随机变量的取值是连…

关于Windows 10的兼容模式,看这篇文章就够了

这篇文章解释了如何使用Windows兼容模式在Windows 10上完美地运行旧版本的Windows程序。 如何更改Windows 10兼容模式设置 如果疑难解答没有完成任务&#xff0c;并且你知道该程序以前使用过哪个版本的Windows&#xff0c;则可以手动更改Windows 10兼容模式的设置&#xff1a…