【C++】--类和对象(3)

🤑个人主页: 起名字真南
🤑个人专栏:【数据结构初阶】 【C语言】 【C++】

请添加图片描述

目录

  • 1 深入构造函数
  • 2 类型转换
  • 3 static成员
  • 4 友元函数
  • 5 内部类
  • 6 匿名对象

1 深入构造函数

  • 之前我们实现构造函数的时候,初始化成员变量都是在函数体内赋值,构造函数初始化还有另一个方式,就是初始化列表,初始化列表的使用方式是从一个冒号开始,成员变量之间用‘ ,’(逗号)分隔开,每个成员变量的后面都有一个括号里面存放着初始化的值或表达式。
  • 每个成员变量都只能在初始化列表中出现一次,可以理解为是每个成员变量进行定义初始化的地方。
  • 引用成员变量,const成员变量,没有默认构造的类类型成员变量,必须放在初始化列表的地方进行初始化,否则会编译报错
  • C++11支持在成员变量声明的地方给缺省值,这个缺省值目的是给没有显示在初始化列表初始化的变量使用的。
  • 使用初始化列表进行初始化,因为即便没有在初始化列表进行初始化编译器同样会经过初始化列表,如果在变量定义的时候给了缺省值那么就会用缺省值进行初始化,如果没有缺省值就会按照括号里的值或表达式进行初始化,对于没有在初始化列表显示的内置类型是否进行初始化却决于编译器,而对于自定义类型则会调用他的默认构造函数,如果没有默认构造就会造成编译报错。
  • 初始化列表的初始化顺序与该成员变量在初始化列表中的顺序无关,至于这个变量的声明顺序有关,先声明的先初始化。
    总结 :
    无论是否写初始化列表,每个构造函数都有初始化列表。
    无论是否在初始化列表显示初始化,每个成员变量都会走一遍初始化列表。

在这里插入图片描述

#include<iostream>
using namespace std;class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};
class Date
{
public:Date(int& x, int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day), _t(12), _ret(x), _n(1){//只能在初始化列表初始化,不能再函数体内进行初始化//_ret = x;//_t = 12;//_n = 1;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;// 以下变量能且只能在初始化列表进行初始化Time _t;       //类类型成员变量   没有默认构造int& _ret;     //引用成员变量   const int _n;  //const类型成员变量
};
int main()
{int i = 0;Date d1(i);d1.Print();return 0;
}

运行结果如下:
在这里插入图片描述
虽然Time类型的成员变量都是内置类型成员变量,并且在初始化的时候可以不写默认构造但是由于在Time中已经写了一个构造函数所以不会生成默认构造,而在Date类中作为了自定义类类型的成员变量如果没有在初始化列表中初始化就会调用他的默认构造,因为它没有默认构造就会报错。
如果把初始化列表中的Time删除就会出现下面的错误:
在这里插入图片描述

class Time
{
public:Time(int hour):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};
class Date
{
public:Date():_month(1){cout << "Date()" << endl;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year = 1;int _month = 1;int _day;// 注意这里不是初始化而是给初始化列表提供了缺省值//如果初始化列表没有显示初始化,就是用这个缺省值初始化Time _t = 1;       int* _ret = (int*)malloc(sizeof(int) * 3);      const int _n = 1; 
};
int main()
{Date d1;d1.Print();return 0;
}

运行结果如下:
在这里插入图片描述

2 类型转换

  • C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型作为参数的构造函数
  • 构造函数前面加上explicit就不再支持隐式类型转换
  • 类类型对象之间也可以隐式类型转换,需要相对应的构造函数支持
#include<iostream>
using namespace std;class A
{
public://构造函数explicit就不再支持隐式类型转换// explicit A(int a1)A(int a1):_a1(a1){}A(int a1, int a2):_a1(a1),_a2(a2){}void print(){cout << _a1 << " " << _a2 << endl;}int get() const{return _a1 + _a2;}
private:int _a1 = 1;int _a2 = 2;
};
class B
{
public:B(const A& a):_b(a.get()){}
private:int _b = 0;
};
int main()
{A aa1 = 1;aa1.print();const A& aa2 = 1;//多参数传参用大括号A aa3 = { 3, 3 };aa3.print();cout << aa3.get() << endl;//A 类型 隐式转换为 B类型B b = aa3;const B& rb = aa3;return 0;
}

3 static成员

  • 用static修饰的成员变量叫做静态成员变量,必须要在类外进行初始化
  • 静态成员变量为所有类对象共享,不属于某个具体的对象,不存在对象中,存放在静态区中。
  • 用static修饰的成员函数称为静态成员函数,静态成员函数没有this指针。
  • 静态成员函数中可以访问其他的静态成员,但是不能访问非静态成员因为没有this指针。
  • 非静态成员函数可以访问任意的静态成员变量和静态成员函数
  • 突破类域就可以访问静态成员,可以通过类名::静态成员,对象.静态成员来访问静态成员变量和静态成员函数。
  • 静态成员也受public,private,protected等访问限定符限制。
  • 静态成员函数不能在声明的位置给缺省值进行初始化,因为缺省值是给构造函数初始化列表使用的,静态成员不属于某个对象,不走初始化列表。
#include<iostream>
using namespace std;class A
{
public:A(){++_scount;};A(const A& t){++_scount;}~A(){--_scount;}static int GetCount(){return _scount;}
private://类里面声明static int _scount;
};//类外面初始化
int A::_scount = 0;int main()
{cout << A::GetCount() << endl;A a1, a2;cout << A::GetCount() << endl;A a3(a1);cout << A::GetCount() << endl;cout << a3.GetCount() << endl;return 0;
}

运行结果:
在这里插入图片描述
第一次输出的结果是0,是因为我们在初始化的时候初始化的值为0,然后在每一次调用构造函数的时候就会加1,调用析构的时候减1,我们可以看到构造了a1,a2两个变量所以调用了两次++,然后在使用拷贝构造a3,调用构造函数在++所以这个时候的count是3,每次调用构造函数都会++,然后最后函数销毁时会自动调用析构函数,调用三次。

4 友元函数

  • 友元提供了一种突破类域访问限制的方法,友元分为:友元函数,友元类,在函数声明和类声明前面加上friend,并且把友元声明放到一个类里面。
  • 外部友元函数可以访问内部类的私有和保护变量,友元函数仅仅是一种声明并不是类的成员函数。
  • 友元函数可以在类定义的任何地方声明不受访问限定符的限制。
  • 一个函数可以是多个类的友元函数
  • 友元类的关系是单向的并不是双向的比如A是B的友元,但是B不是A的友元
  • 友元的关系不能传递,比如A是B的友元,B是C的友元,但A不是C的友元
  • 容易破坏封装不宜多用
#include<iostream>
using namespace std;class A; //前置声明为了调用函数的时候可以找到A类
class B
{friend void func(const A& aa, const B& bb);private:int _b1 = 1;int _b2 = 2;
};class A
{friend void func(const A& aa, const B& bb);private:int _a1 = 1;int _a2 = 2;
};void func(const A& aa, const B& bb)
{cout << aa._a1 << endl;cout << bb._b1 << endl;
}
int main()
{A a1, a2;B b1, b2;func(a1, b1);return 0;
}

在写上面的代码我们需要注意一个情况就是关于前置声明,因为编译器只会向上查找,在B类中的友元函数用到了A类所以我们需要在B类的前面提前声明A类告诉编译器A类存在。

class C
{friend class D;
private:int _c1 = 1;int _c2 = 2;
};class D
{
public:void func01(const C& cc){cout << cc._c1 << endl;cout << _d1 << endl;}void func02(const C& cc){cout << cc._c2 << endl;cout << _d2 << endl;}private:int _d1 = 3;int _d2 = 4;
};int main()
{C cc;D dd;dd.func01(cc);dd.func02(cc);return 0;
}

5 内部类

  • 如果一个类定义在一个类的内部,那么这个内部的类就叫做内部类,内部类是一个独立的类,跟定义在全局相比他只受外部类的类域和访问限定符限制,所以外部类定义的对象中不包含内部类。
  • 内部类默认是外部类的友元
  • 内部类本质上也是一种封装,如果A类和B类有紧密的联系,并且A类设计出来是专门为B类使用的那么就可以把B类设计为A类的内部类,B作为内部类可以访问A类的私有成员变量。
class AA
{
public:class BB{public:void func01(const AA& aa){cout << _k << endl;cout << aa._x << endl;}};
private:static int _k;int _x = 1;
};int AA:: _k = 2;int main()
{cout << sizeof(AA) << endl;AA aa;AA::BB bb;bb.func01(aa);return 0;
}

结果展示:
在这里插入图片描述
这里sizeof的大小是4的原因是_k是在静态区不算做A类里面

6 匿名对象

  • 用类型(实参)定义出来的对象叫做匿名对象,用类型 对象名 定义出来的对象叫做有名对象
  • 匿名对象的生命周期只在当前一行。
class AAA
{
public:AAA(int a = 0):_a(a){cout << "AAA(int a)" << endl;}~AAA(){cout << "~AAA()" << endl;}
private:int _a;
};
class Solution {
public:int Sum_Solution(int n) {//...return n;}
};
int main()
{//匿名对象的定义AAA();AAA(1);//有名对象AAA a2(2);Solution().Sum_Solution(10);return 0;
}

运行结果:
在这里插入图片描述
这里分别调用了三次构造三次析构证明对象确实存在生命周期只存在一行在下一个对象创建之后就已经销毁调用了析构

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

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

相关文章

selenium有多个frame页时的操作方法(5)

之前文章我们提到&#xff0c;在webdriver.WebDriver类有一个switch_to方法&#xff0c;通过switch_to.frame()可以切换到不同的frame页然后才再定位某个元素做一些输入/点击等操作。 比如下面这个测试网站有2个frame页&#xff1a;http://www.sahitest.com/demo/framesTest.h…

5.toString()、构造方法、垃圾回收、静态变量与静态方法、单例设计模式、内部类

文章目录 一、toString()1. 优缺点2. 使用方法举例① Dos类里更省事的方法 ② Application里 二、构造方法1. 导入2. 什么是构造方法3. 怎么写构造方法① 无参的构造方法(无参构造器)② 有参的构造方法(有参构造器)③ 注意 4. 构造方法的重载 三、再探this1. 给成员变量用2. 给…

【用户管理 添加用户 超级用户 用户和组】

用户管理 添加用户超级用户用户和组 添加用户 介绍用户的管理操作 比如&#xff0c;添加一个用户 sudo useradd -m test1 其中&#xff0c;sudo表示管理员身份运行 修改用户密码 sudo passwd test1 删除用户 sudo userdel test 超级用户 1.首次使用时&#xff0c;需要给roo…

快速区分 GPT-3.5 与 GPT-4

问&#xff1a;鲁迅为什么暴打周树人&#xff1f; GPT3.5回答 各种稀奇古怪的理由 GPT4回答 正确区分鲁迅和周树人是同一个人 国内GPT入口 https://ai-to.cn/url/?ulihaimao

Android Preference的使用以及解析

简单使用 values.arrays.xml <?xml version"1.0" encoding"utf-8"?> <resources><string-array name"list_entries"><item>Option 1</item><item>Option 2</item><item>Option 3</item&…

初始Linux(二)基础命令

前言&#xff1a; 之前那一篇我们已经介绍了一部分的基础命令&#xff0c;当然那只不过是九牛一毛&#xff0c;本篇我们继续介绍一些比较重要且需要掌握的基础命令。 mv命令&#xff1a; 其实这个命令有两个功能&#xff0c;一个是移动&#xff08;剪切&#xff09;文件&#…

linux如何与网络时间对齐(雪花算法ID重复)

文章目录 前言一、可能引发什么问题&#xff1f;二、调整步骤1.查看当前系统时间2.修改为中国时区3.同步网络时间4. 雪花id重复 总结 前言 linux服务器是部署服务的不二之选,有个小问题不可忽略&#xff1a; 会发现默认的服务器时间并非中国时区,时间也是相差八小时,中国时区…

(笔记)第三期书生·浦语大模型实战营(十一卷王场)–书生基础岛第5关---XTuner 微调个人小助手认知

学员闯关手册&#xff1a;https://aicarrier.feishu.cn/wiki/ZcgkwqteZi9s4ZkYr0Gcayg1n1g?open_in_browsertrue 课程视频&#xff1a;https://www.bilibili.com/video/BV1tz421B72y/ 课程文档&#xff1a; https://github.com/InternLM/Tutorial/tree/camp3/docs/L1/XTuner 关…

ThreadLocal原理解析及面试

基本使用 讲原理之前&#xff0c;我简单写个demo小程序说说怎么使用 public class TestThreadLocal {public static void main(String[] args) throws InterruptedException {ThreadLocal<String> tl new ThreadLocal();/**主线程设置了一个值*/tl.set("SSSSSs&…

Java生成二维码示例(带logo以及文字描述)

先看一下生成效果 普通二维码 普通带文本二维码 带logo二维码 带logo带文本二维码 直接上代码 这里主要是用的第三方工具生成二维码的&#xff0c;所以我们需要先引入 jar 包 <dependency><groupId>com.google.zxing</groupId><artifactId>core</…

2024诺贝尔生理学或医学奖:RNA技术将拯救人类世界

生信碱移 miRNA领域获得最新诺贝尔奖 “我好像接到了真的诺贝尔委员会的电话&#xff01;” 加里鲁夫坎 2024年诺贝尔医学奖得主 ▲ 两位诺贝尔奖获奖得主。来源:诺贝尔生理学或医学奖委员会。 就在今天&#xff0c;卡罗林斯卡学院的诺贝尔大会决定将2024年诺贝尔生理学或医学…

动手学深度学习(李沐)PyTorch 第 6 章 卷积神经网络

李宏毅-卷积神经网络CNN 如果使用全连接层&#xff1a;第一层的weight就有3*10^7个 观察 1&#xff1a;检测模式不需要整张图像 很多重要的pattern只要看小范围即可 简化1&#xff1a;感受野 根据观察1 可以做第1个简化&#xff0c;卷积神经网络会设定一个区域&#xff0c…

无人机之飞行算法篇

无人机的飞行算法是一个复杂而精细的系统&#xff0c;它涵盖了多个关键技术和算法&#xff0c;以确保无人机能够稳定、准确地执行飞行任务。 一、位置估计 无人机在空中飞行过程中需要实时获取其位置信息&#xff0c;以便进行路径规划和控制。这通常通过以下传感器实现&#…

基于STM32的模拟舞台灯光控制系统设计

引言 本项目设计了一个基于STM32的模拟舞台灯光控制系统&#xff0c;可以通过调节灯光的亮度、颜色和模式&#xff0c;实现多种灯光效果模拟&#xff0c;如渐变、闪烁和跟随节奏的灯光变化。该系统结合了LED灯条、PWM控制和按钮输入等&#xff0c;实现了舞台灯光的多样化展示。…

【Linux的那些事】shell命名及Linux权限的理解

目录 一、shell命令以及运行原理 二、Linux权限的概念 三、Linux权限管理 3.1.文件访问者的分类&#xff08;人&#xff09; 3.2.文件类型和访问权限&#xff08;事物属性&#xff09; 3.3.文件权限值的表示方法 3.4.文件访问权限的相关设置方法 a)chmod b)chown c)…

5.错误处理在存储过程中的重要性(5/10)

错误处理在存储过程中的重要性 引言 在数据库编程中&#xff0c;存储过程是一种重要的组件&#xff0c;它允许用户将一系列SQL语句封装成一个单元&#xff0c;以便重用和简化数据库操作。然而&#xff0c;像任何编程任务一样&#xff0c;存储过程中的代码可能会遇到错误或异常…

使用MTVerseXR SDK实现VR串流

1、概述​ MTVerseXR SDK 是摩尔线程GPU加速的虚拟现实&#xff08;VR&#xff09;流媒体平台&#xff0c;专门用于从远程服务器流式传输基于标准OpenXR的应用程序。MTVerseXR可以通过Wi-Fi和USB流式将VR内容从Windows服务器流式传输到XR客户端设备, 使相对性能低的VR客户端可…

15分钟学 Python 第38天 :Python 爬虫入门(四)

Day38 : Python爬虫异常处理与反爬虫机制 章节1&#xff1a;异常处理的重要性 在爬虫开发过程中&#xff0c;网络请求和数据解析常常会遭遇各种异常。正确的异常处理可以提高程序的稳定性&#xff0c;避免崩溃&#xff0c;并帮助开发者快速定位问题。 章节2&#xff1a;常见…

18710 统计不同数字的个数(升级版)

### 思路 为了快速判断某个数字是否在之前出现过&#xff0c;我们可以使用一个布尔数组来记录每个数字是否已经出现过。由于题目中给出了数字的范围&#xff08;0 < ai < 200000&#xff09;&#xff0c;我们可以开一个大小为200001的布尔数组来记录每个数字的出现情况。…

网络编程(15)——服务器如何主动退出

十五、day15 服务器主动退出一直是服务器设计必须考虑的一个方向&#xff0c;旨在能通过捕获信号使服务器安全退出。我们可以通过asio提供的信号机制绑定回调函数即可实现优雅退出。 之前服务器的主函数如下 #include "CSession.h" #include "CServer.h"…