【C++】类和对象(下篇)

这里是目录

  • 构造函数(续)
    • 构造函数体赋值
    • 初始化列表
  • explicit关键字
    • 隐式类型转换
  • static成员
  • 友元
    • 友元函数
    • 友元类
  • 内部类
  • 匿名对象
      • 匿名对象的作用
      • const引用匿名对象

构造函数(续)

构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};

初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式

class A
{
public:A(int a):_a(a){}
private:int _a;
};class B
{
public://初始化列表:对象的成员定义的位置B(int a, int& ref):_aobj(a),_ref(ref),_n(10){}
private://声明A _aobj; // 没有默认构造函数//特征:必须在定义的时候初始化int& _ref; // 引用const int _n; // const 
};int main()
{int x = 20;B b1(10,x);return 0;
}

注意:

每个成员变量在初始化列表中最多只能出现一次(初始化只能初始化一次)
类中包含以下成员,必须放在初始化列表位置进行初始化:

  1. 引用成员变量
  2. const成员变量
  3. 自定义类型成员(且该类没有默认构造函数时)

尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};int main()
{A a(1);a.Print();return 0;
}

运行结果:
在这里插入图片描述
这里的声明顺序是a2 - a1所以在初始化的时候就是先初始化a2(随机值)再初始化a1

建议声明的顺序和定义的顺序保持一致,可以减少错误的发生

explicit关键字

隐式类型转换

class A
{
public:A(int a):_a(a){}private:int _a;
};
int main()
{A a1(1);A a2 = 2;//隐式类型转换,一个整型转换成自定义类型//2构造一个A的临时对象,临时对象再拷贝构造a2 -->优化为用2直接构造//临时对象具有常性,需要加constconst A& a3 = 3;//这里也会发生隐式类型转换return 0;
}

那如果我们不希望发生转换该怎么处理
那么就可以加上 explicit

class A
{
public:explicit A(int a):_a(a){}private:int _a;
};
int main()
{A a1(1);A a2 = 2;//隐式类型转换,一个整型转换成自定义类型//2构造一个A的临时对象,临时对象再拷贝构造a2 -->优化为用2直接构造//临时对象具有常性,需要加constconst A& a3 = 3;//这里也会发生隐式类型转换return 0;
}

加上了 explicit就无法发生隐式转换因此这段代码就会报错
在这里插入图片描述


static成员

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化

class A
{
public:A(){ }A(const A& t) { }~A() { }private:};

我们想知道当前还有多少个A对象正在使用该怎么办?
我们可以使用全局变量进行统计,构造一次加一,析构一次减一

int _count = 0;class A
{
public:A(){ ++_count;}A(const A& t) { ++_count;}~A() { --_count;}private:};int main()
{//全局变量的劣势 - 任何地方都可以随意改变_count++;return 0;
}

但是全局变量有一个劣势,就是任何地方都可以对他进行修改,这样的数据就会非常不安全
那么我们就可以把我们的数据封装在类里面

class A
{
public:A()//不能这样定义,因为他不是属于某个对象的成员,他是属于全局的//:_count(0);{ ++_count;}A(const A& t) { ++_count;}~A() { --_count;}//因为是私有的数据,所以需要一个共有的成员函数来访问//静态成员函数 - 特点:没有this指针,指定类域和访问限定符就可以访问//静态成员变量和静态成员函数一般是配套出现的static int GetCount(){return _count;}
private://成员变量 - 存储在对象里面int _a = 1;int _b = 2;//静态成员变量 - 存储在静态区//同理这里也是声明,也是需要在类外面定义static int _count;//区别:成员变量 - 属于每一个类对象//静态成员变量 - 属于类,属于类的每个对象共享
};//全局位置,类外面定义(可以突破一次私有)
int A::_count = 0;void Func()
{static A a2;cout << __LINE__ << "-" << A::GetCount() << endl;
}
int main()
{A a1;cout << __LINE__ << "-" << A::GetCount() << endl;Func();Func();return 0;
}

__LINE__显示当前行数

运行效果:

在这里插入图片描述

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

友元

友元提供了一种突破封装的方式,有时提供了便利,但是友元会增加耦合度,破坏了封装,所以友元不宜多用

友元函数

class Date
{//友元函数声明//友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类//但需要在类的内部声明,声明时需要加friend关键字friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}int main()
{Date d;//可以直接访问私有cin >> d;cout << d << endl;return 0;
}

运行效果:
在这里插入图片描述

友元函数可访问类的私有和保护成员,但不是类的成员函数
友元函数不能用const修饰
友元函数可以在类定义的任何地方声明,不受类访问限定符限制
一个函数可以是多个类的友元函数
友元函数的调用与普通函数的调用原理相同

友元类

class Time
{//声明Date类为Time的友元类,在Date类中就直接访问Time类中的私有成员变量friend class Date; 
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}private:int _hour;int _minute;int _second;
};class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}void Print(){cout << _t._hour << "-" << _t._minute << "-" << _t._second << endl;}private:int _year;int _month;int _day;Time _t;
};int main()
{//可以在Date类中直接访问Time类的私有成员变量//但在Time类中访问Date类中私有的成员变量则不行Date d1;//通过Date类设置Time类的私有成员d1.SetTimeOfDate(22, 30, 10);//通过Date类访问Time类的私有成员d1.Print();return 0;
}

运行效果:
在这里插入图片描述

友元关系不能传递
如果B是A的友元,C是B的友元,则不能说明C时A的友元
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员

内部类

如果一个类定义在另一个类的内部,这个内部类就叫做内部类, 内部类可以是公有、私有、保护

class A
{
private:static int k;int h;
public:class B //内部类是外部类的友元{public:private:int b;};
};int A::k = 1;int main()
{cout << sizeof(A) << endl;return 0;
}

运行结果:
在这里插入图片描述
从结果可以看到B类虽然定义在了A类里面,但是B类并不占用空间
内部类是外部类的友元,所以我们可以通过B类访问A类的成员

class A
{
private:static int _k;int _h = 20;
public:class B //内部类是外部类的友元 - B可以访问A,A不能访问B{public:void Print(const A& a){cout << a._k << endl;//OK//内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名cout << _k << endl;//OKcout << a._h << endl;//OKcout << _b << endl;}private:int _b = 30;};
};int A::_k = 10;int main()
{A a1;//内部类实例化//如果内部类为私有则无法实例化A::B b1;b1.Print(a1);return 0;
}

运行效果:
在这里插入图片描述

匿名对象

class A
{
public:A(int a = 0):_a(a){cout << "调用构造函数" << endl;}~A(){cout << "调用析构函数" << endl;}private:int _a;
};int main()
{A a1(1);//有名对象A(2);//匿名对象(没有名字)return 0;
}

运行效果:
在这里插入图片描述

匿名对象的作用

class A
{
public:A(int a = 0):_a(a){cout << "调用构造函数" << endl;}~A(){cout << "调用析构函数" << endl;}private:int _a;
};class Solution
{
public:int Sum_Solution(int n){cout << "已调用Sum_Solution" << endl;return n;}
};int main()
{A a1(1);//有名对象A(2);//匿名对象(没有名字)//如果我们想调用Sum_Solution//可以这样调用Solution s;s.Sum_Solution(10);//还可以使用匿名对象调用//如果只想调用一次则可以使用这种方法//类型不能调用函数,需要加()//如果没有默认构造则需要传参(有几个参数就传几个) - Solution(1).Sum_Solution(20);Solution().Sum_Solution(20);return 0;
}

运行效果:
在这里插入图片描述

从运行结果还可以看出,匿名对象的生命周期只在当前行,而有名对象的生命周期在当前函数局部域
匿名对象和临时对象一样具有常性

const引用匿名对象

虽然匿名对象的生命周期只在当前行,但是const引用会延长匿名对象的生命周期(生命周期在当前函数局部域)

class A
{
public:A(int a = 0):_a(a){cout << "调用构造函数" << endl;}~A(){cout << "调用析构函数" << endl;}private:int _a;
};class Solution
{
public:int Sum_Solution(int n){cout << "已调用Sum_Solution" << endl;return n;}
};int main()
{A a1(1);//有名对象A(2);//匿名对象(没有名字)//A& ra = A(3); //匿名对象具有常性const A& ra = A(4);Solution().Sum_Solution(20);return 0;
}

运行效果:
在这里插入图片描述
在这里插入图片描述
补充:编译器的优化

class A
{
public:A(int a = 0):_a(a){cout << "调用构造函数" << endl;}~A(){cout << "调用析构函数" << endl;}private:int _a;
};A Func()
{A aa;return aa;
}int main()
{//编译器会对连续的构造进行优化A a1 = Func(); //拷贝构造+拷贝构造 ->优化为拷贝构造cout << "-------------" << endl;//这种写法干扰了编译器的优化A a2;a2 = Func();//这种写法编译器不会进行优化,应该避免这种写法return 0;
}

运行效果:
在这里插入图片描述


以上就是本篇文章的全部内容了,希望大家看完能有所收获

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

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

相关文章

五种多目标优化算法(MOGWO、MOLPB、MOJS、NSGA3、MOPSO)求解微电网多目标优化调度(MATLAB代码)

一、多目标优化算法简介 &#xff08;1&#xff09;多目标灰狼优化算法MOGWO 多目标应用&#xff1a;基于多目标灰狼优化算法MOGWO求解微电网多目标优化调度&#xff08;MATLAB代码&#xff09;-CSDN博客 &#xff08;2&#xff09;多目标学习者行为优化算法MOLPB 多目标学习…

佳易王幼儿园缴费系统软件编程应用实例

佳易王幼儿园缴费系统软件编程实例 佳易王幼儿园缴费系统功能&#xff1a; 1、系统设置 2、班级设置 3、其他费用名称 4、学生信息管理 5、学生缴费 6、统计报表 7、备份全部数据 软件试用版下载可以点击下方官网卡片

由走“贸工技”的联想联想到传统OEM,带给了自己那些思考?

2022年1月16日&#xff0c;自己来到魔都的第1597天&#xff0c;这城市还是保持着相似的容颜&#xff0c;而自己却悄悄的起了变化。 以前对时间概念其实不是特别敏感&#xff0c;感觉自己有大把的时光可以浪费&#xff08;虽然知道死亡是个永远无法逃避的话题&#xff09;&#…

MATLAB 和 Simulink 官方文档下载地址

MATLAB 官方文档中文版下载网址&#xff1a; https://ww2.mathworks.cn/help/pdf_doc/matlab/index.html 如图&#xff1a; MATLAB 官方文档英文版下载网址&#xff1a; https://ww2.mathworks.cn/help/pdf_doc/matlab/index.html?langen 如图&#xff1a; Simulink 官…

Vue - Vue配置proxy代理,开发、测试、生产环境

1、新建三个环境的配置文件 在src同级目录也就是根目录下新建文件&#xff1a;.env.development&#xff08;开发环境&#xff09;、.env.test&#xff08;测试环境&#xff09;、.env.production文件&#xff08;生产环境&#xff09; 2、三个环境的配置文件 开发环境 .env…

重量级消息,微软将ThreadX RTOS全家桶贡献给Eclipse基金会,免费供大家商用,宽松的MIT授权方式

从明年第1季度开始&#xff0c;任何人&#xff0c;任何厂家的芯片都可以免费商用&#xff0c;MIT授权就这点好。 贡献出来后&#xff0c;多方可以一起努力开发&#xff0c;当前首批兴趣小组AMD, Cypherbridge, Microsoft, NXP, PX5, Renesas, ST Microelectronics, Silicon Lab…

cephadm部署ceph quincy版本,使用ceph-csi连接

环境说明 IP主机名角色 存储设备 192.168.2.100 master100 mon,mgr,osd,mds,rgw 大于5G的空设备192.168.2.101node101mon,mgr,osd,mds,rgw大于5G的空设备192.168.2.102node102mon,mgr,osd,mds,rgw大于5G的空设备 关闭防火墙 关闭并且禁用selinux 配置主机名/etc/hosts …

HarmonyOS(五)—— 认识页面和自定义组件生命周期

前言 在前面我们通过如何创建自定义组件一文知道了如何如何自定义组件以及自定义组件的相关注意事项&#xff0c;接下来我们认识一下页面和自定义组件生命周期。 自定义组件和页面的关系 在开始之前&#xff0c;我们先明确自定义组件和页面的关系 自定义组件&#xff1a;Co…

【案例讲解】LVGL 如何用LVGL画加载圈

更多源码分析请访问:LVGL 源码分析大全 目录 1、概述2、实现效果图3、实现思路4、代码详解1、概述 很多场景下,在用户操作时,需要使用一个加载圈来缓解用户焦虑问题。 2、实现效果图 3、实现思路 用八个固定的圆点来表示加载圈,当使这八个圈依次隐藏和显示,这样就能做…

基于helm的方式在k8s集群中部署gitlab - 部署(一)

文章目录 1. 背景说明2. 你可以学到什么&#xff1f;3. 前置条件4. 安装docker服务&#xff08;所有节点&#xff09;5. 部署k8s集群5.1 系统配置&#xff08;所有节点&#xff09;5.2 安装kubelet组件(所有节点)5.2.1 编写kubelet源5.2.2 安装kubelet5.2.3 启动kubelet 5.3 集…

基于helm的方式在k8s集群中部署gitlab - 备份恢复(二)

接上一篇 基于helm的方式在k8s集群中部署gitlab - 部署&#xff08;一&#xff09;&#xff0c;本篇重点介绍在k8s集群中备份gitlab的数据&#xff0c;并在虚拟机上部署相同版本的gitlab&#xff0c;然后将备份的数据进行还原恢复 文章目录 1. 备份2. 恢复到虚拟机上的gitlab2.…

【Git】git 更换远程仓库地址三种方法总结分享

因为公司更改了 gitlab 的网段地址&#xff0c;发现全部项目都需要重新更改远程仓库的地址了&#xff0c;所以做了个记录&#xff0c;说不定以后还会用到呢。 一、不删除远程仓库修改&#xff08;最方便&#xff09; # 查看远端地址 git remote -v # 查看远端仓库名 git rem…

牛客网刷题笔记四 链表节点k个一组翻转

NC50 链表中的节点每k个一组翻转 题目&#xff1a; 思路&#xff1a; 这种题目比较习惯现在草稿本涂涂画画链表处理过程。整体思路是赋值新的链表&#xff0c;用游离指针遍历原始链表进行翻转操作&#xff0c;当游离个数等于k时&#xff0c;就将翻转后的链表接到新的链表后&am…

歌曲《兄弟情深》:歌手荆涛歌曲中的真挚情感

在人生的道路上&#xff0c;有时我们会遇到迷茫、失落、困惑等种种情境。而在这些时刻&#xff0c;身边有一个真挚的兄弟&#xff0c;其意义是无法估量的。歌手荆涛演唱的《兄弟情深》即是对这种深厚情感的美妙歌颂。 一、迷茫时的指引 “当我迷茫时&#xff0c;有你帮目标重新…

这是一张单纯的图片-MISC-bugku-解题步骤

——CTF解题专栏—— 题目信息&#xff1a; 题目&#xff1a;这是一张单纯的图片 作者&#xff1a;harry 提示&#xff1a;无 解题附件&#xff1a; 解题思路&#xff1a; 图片解题三板斧winwalk、010Editor、Stegsolve&#xff0c;一一尝试。 解题步骤&#xff1a; 一、wi…

emu8086汇编语言输出“Hello World!“

输出Hello world 首先我们尝试用C语言来实现该功能&#xff1a; #include <stdio.h>int main() {printf("Hello World!"); // 输出“Hello World!”return 0; } 将这行代码翻译成汇编语言... ; DS 数据段定义 DATA SEGMENTZIFU DB Hello World!,$ ;字符串…

2016年五一杯数学建模A题购房中的数学问题解题全过程文档及程序(采光与房款)

2016年五一杯数学建模 A题 购房中的数学问题 原题再现 随着现代社会经济的快速发展&#xff0c;房地产成为国家经济发展中重要的经济增长点之一。为了充分利用楼房建设的土地面积&#xff0c;开发商经常会选择建筑高层住宅。在购买住房时&#xff0c;影响消费者选择购房的因素…

深入理解数据结构:链表

文章目录 &#x1f330;导语&#x1f330;链表的定义及基本结构&#x1f330;单链表&#x1f955;单链表特点 &#x1f330;双向链表&#x1f955;双链表特点 &#x1f330;循环链表&#x1f955;循环链表特点 &#x1f330;链表的操作&#x1f346;链表的插入&#x1fad8;链头…

Git 仓库越来越大?不要慌!试试这个简单方法,轻松秒瘦身

开局两张图 瘦身前瘦身后 目录 开局两张图前言下载 BFG克隆代码Git 仓库瘦身清理存储库储存库 GC推送仓库 Git 瘦身验证结语开源项目 前言 在进行项目开发的过程中&#xff0c;代码仓库的体积可能会逐渐增大&#xff0c;特别是在版本控制系统中保留了大量的历史提交记录和不必…

YOLOv5算法进阶改进(4)— 引入解耦合头部 | 助力提高检测准确率

前言:Hello大家好,我是小哥谈。解耦头是目标检测中的一种头部设计,用于从检测网络的特征图中提取目标位置和类别信息。具体来说,解耦头部将目标检测任务分解为两个子任务:分类和回归。分类任务用于预测目标的类别,回归任务用于预测目标的位置。这种设计可以提高目标检测的…