【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. 给…

数据结构——排序(交换排序)

目录 一、交换排序的总体概念 二、冒泡排序 三、快速排序 1.挖坑法 2.左右指针 3.前后指针 一、交换排序的总体概念 交换排序是一类排序算法&#xff0c;它的核心思想是通过交换元素的位置来达到排序的目的。在排序过程中&#xff0c;比较数组中的元素对&#xff0c;如果…

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

用户管理 添加用户超级用户用户和组 添加用户 介绍用户的管理操作 比如&#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

​nginx负载均衡的五种算法​

一、Nginx负载均衡算法 1、轮询&#xff08;默认&#xff09; 每个请求按时间顺序逐一分配到不同的后端服务&#xff0c;如果后端某台服务器死机&#xff0c;自动剔除故障系统&#xff0c;使用户访问不受影响。 例如&#xff1a; upstream bakend { server 192.168.0.1; …

React常见面试题目

React常见面试题目详解包括以下几个方面&#xff1a; 1. 对React的理解及特性 定义与用途&#xff1a;React是一个用于构建用户界面的JavaScript库&#xff0c;它遵循组件设计模式、声明式编程范式和函数式编程概念&#xff0c;使得前端应用程序更高效。 核心特性&#xff1a; …

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&…

Hadoop krb5.conf 配置详解

krb5.conf文件是Kerberos认证系统中的一个关键配置文件&#xff0c;它包含了Kerberos的配置信息&#xff0c;如KDC&#xff08;Key Distribution Centers&#xff09;和Kerberos相关域的管理员服务器位置、当前域和Kerberos应用的默认设置、以及主机名与Kerberos域的映射等。以…

初始Linux(二)基础命令

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

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

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

计算物理精解【11】-计算原理精解【8】

文章目录 马尔科夫过程论基础理论函数系的定义、例子和分类一、函数系的定义二、函数系的例子三、函数系的分类 什么是测度定义性质种类应用总结 计算测度的公式1. 长度&#xff08;一维测度&#xff09;2. 面积&#xff08;二维测度&#xff09;3. 体积&#xff08;三维测度&a…

vscode提交修改Failed to connect to github.com port 443: Timed out

参考内容&#xff1a;timed out 只需3步&#xff1a;设置代理、取消代理、再次提交。&#x1f449; 2.1 设置代理 $ git config --global https.proxy 1 &#x1f449; 2.2 取消代理 $ git config --global --unset https.proxy 1之后关闭bash&#xff0c;再去vscode里面pull …

(笔记)第三期书生·浦语大模型实战营(十一卷王场)–书生基础岛第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 关…

《C++职场中设计模式的学习与应用:开启高效编程之旅》

在 C职场中&#xff0c;设计模式是提升代码质量、增强程序可维护性和可扩展性的强大武器。掌握并正确应用设计模式&#xff0c;不仅能让你在工作中更加得心应手&#xff0c;还能为你的职业发展增添有力的砝码。那么&#xff0c;如何在 C职场中学习和应用设计模式呢&#xff1f;…

ThreadLocal原理解析及面试

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

头歌实践教学平台 大数据编程 实训答案(三)

第一章 遍历日志数据 用 Spark 遍历日志数据 第1关:用 Spark 获得日志文件中记录总数 任务描述 本关任务:编写一个能用 Spark 操作日志文件并输出日志文件记录数的小程序。 相关知识 为了完成本关任务,你需要掌握:1.搜索查询日志的内容,2.如何用 Spark 获得日志文件,3…

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…