【C++干货篇】——类和对象的魅力(四)

news2024/11/25 15:00:05

【C++干货篇】——类和对象的魅力(四)

1.取地址运算符的重载

1.1const 成员函数

  • 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后面。
  • const实际修饰该成员函数隐含的this指针(this指向的对象),表明在该成员函数中不能对类的任何成员进行修改。const 修饰Date类的Print成员函数,Print隐含的this指针由 Date* const this 变为 const Date* const this:
#include<iostream>
using namespace std;
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	// void Print(const Date* const this) const
	void Print() const
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	// 这⾥⾮const对象也可以调⽤const成员函数是⼀种权限的缩⼩
	Date d1(2024, 7, 5);
    //&d1->Date*
	d1.Print();

	const Date d2(2024, 8, 5);
    //&d->const Date*
	d2.Print();

	return 0;
}

总结:

  • const 修饰指向的内容时和非const 拷贝赋值才涉及权限放大和缩小问题

  • 一个成员函数,不修改成员变量的建议都加上const.

1.2取地址运算符重载

取地址运算符重载分为普通取地址运算符重载const取地址运算符重载,⼀般这两个函数编译器⾃动⽣成的就可以够我们用了,不需要去显时实现。除非⼀些很特殊的场景,比如我们不想让别⼈取到当前类对象的地址,就可以⾃⼰实现⼀份,胡乱返回⼀个地址。

class Date
{
public :
    Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
    Date* operator&()
    {
        return this;
      // return nullptr;
    }
    
    const Date* operator&()const
    {
        return this;
       // return nullptr;
    }
private :
    int _year ; // 年
    int _month ; // ⽉
    int _day ; // ⽇
};
int main()
{
	const Date d1(2024, 8, 10);
	Date d3(2024, 8, 10);

	cout << &d1 << endl;
	cout << &d3 << endl;

	return 0;
}

在这里插入图片描述

2.再探构造函数

  • 之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种方式,就是初始化列表初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。

    在这里插入图片描述

  • 每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。

  • 引用成员变量(引用必须在定义的时候初始化)、const成员变量(const变量必须初始化;const是不能修改的,唯一一次修改的机会是在初始化的时候)、没有默认构造的类类型的成员变量,必须放在初始化列表位置进⾏初始化,否则会编译报错。

  • C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的成员使⽤的。

  • 尽量使用初始化列表初始化,因为那些你不在初始化列表初始化的成员也会走初始化列表

    如果这个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化;

    如果你没有给缺省值,对于没有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定;

    对于没有显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构造会编译错误。

  • 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序无关。建议声明顺序和初始化列表顺序保持⼀致

在这里插入图片描述

初始化列表总结:

无论是否显示写初始化列表,每个构造函数都有初始化列表;

无论是否在初始化列表显示初始化,每个成员变量都要走初始化列表初始化;

3.类型转换

  • C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。

  • 构造函数前⾯加explicit就不再⽀持隐式类型转换。

  • 类类型的对象之间也可以隐式转换,需要相应的构造函数⽀持

#include<iostream>
using namespace std;

class A
{
public:
	// 构造函数explicit就不再⽀持隐式类型转换
	// explicit A(int a1)
	A(int a1)
		:_a1(a1)
	{
		cout << "A(int a1)" << endl;
	}
	//explicit A(int a1, int a2)
	A(int a1, int a2)
		:_a1(a1)
		, _a2(a2)
	{
	}
	A(const A&aa)
		:_a1(_a1)
		,_a2(_a2)
	{
		cout << "A(const A&aa)" << endl;
	}
	void Print()
	{
		cout << _a1 << " " << _a2 << endl;
	}
	int Get() const
	{
		return _a1 + _a2;
	}
private:
	int _a1 = -1;
	int _a2 = -1;
};

class B
{
public:
	B(const A& a)
		:_b(a.Get())
	{}
private:
	int _b = 0;
};

//内置类型->自定义类型的转化
//自定义类型->自定义类型
int main()
{
	// 1构造⼀个A的临时对象,再⽤这个临时对象拷⻉构造aa3
	// 编译器遇到连续构造+拷⻉构造->优化为直接构造
	A aa1 = 1;
	aa1.Print();

	const A& aa2 = 1;
    // C++11之后才⽀持多参数转化
	A aa3 = (1, 1);

    // aa3隐式类型转换为b对象
    // 原理跟上⾯类似
	B b = aa3;
	const B& rb = aa3;

	return 0;
}

4.static成员

  • ⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。

  • 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。

  • ⽤static修饰的成员函数,称之为静态成员函数静态成员函数没有this指针

  • 静态成员函数中可以访问其他的静态成员,但是不能访问非静态的,因为没有this指针

  • 非静态的成员函数,可以访问任意的静态成员变量和静态成员函数。

  • 突破类域就可以访问静态成员,可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。

  • 静态成员也是类的成员,受public、protected、private 访问限定符的限制

  • 静态成员变量不能在声明位置给缺省值初始化因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{
		++_scount;
	}
	A(const A& t)
	{
		++_scount;
	}

	~A()
	{
		--_scount;
	}

	static int GetACount()
	{
		return _scount;
	}

private:
	// 类⾥⾯声明
	static int _scount;
};

// 类外⾯初始化
int A::_scount = 0;

int main()
{
    cout << A::GetACount() << endl;
    
	A a1, a2;	
    A a3(a1);
    cout << A::GetACount() << endl;
    cout << a1.GetACount() << endl;
// 编译报错:error C2248: “A::_scount”: ⽆法访问 private 成员(在“A”类中声明)
//cout << A::_scount << endl;
	return 0;
}

5.友元

  • 友元提供了⼀种突破 类访问限定符 封装的⽅式,友元分为:友元函数和友元类在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。

  • 外部友元函数可访问类的私有和保护成员友元函数仅仅是⼀种声明,他不是类的成员函数。

  • 友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制

  • ⼀个函数可以是 多个 类的友元函数

  • 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。

  • 友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。

  • 友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是C的友元。

  • 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

测试代码:

#include<iostream>
using namespace std;

// 前置声明,都则A的友元函数声明编译器不认识B
class B;
class A
{
    // 友元声明
    friend void func(const A& aa, const B& bb);
private:
    int _a1 = 1;
    int _a2 = 2;
};

class B
{
    // 友元声明
    friend void func(const A& aa, const B& bb);
private:
    int _b1 = 3;
    int _b2 = 4;
};

void func(const A& aa, const B& bb)
{
    cout << aa._a1 << endl;
    cout << bb._b1 << endl;
}

int main()
{
    A aa;
    B bb;
    func(aa, bb);
    return 0;
}
#include<iostream>
using namespace std;

class A
{
    // 友元声明
    friend class B;
private:
    int _a1 = 1;
    int _a2 = 2;
};

class B
{
public:
    void func1(const A& aa)
    {
        cout << aa._a1 << endl;
        cout << _b1 << endl;
    }
    void func2(const A& aa)
    {
        cout << aa._a2 << endl;
        cout << _b2 << endl;
    }
private:
    int _b1 = 3;
    int _b2 = 4;
};

int main()
{
    A aa;
    B bb;
    bb.func1(aa);
    bb.func1(aa);
    return 0;
}

最后,本篇文章到此结束,感觉不错的友友们可以一键三连支持一下笔者,有任何问题欢迎在评论区留言哦~

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

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

相关文章

Flutter Container容器组件实战案例

The Container widget is your design toolkit. It’s like the master builder that helps you structure and style your UI elements with precision. Whether you’re creating simple designs or complex layouts, the Container is your trusty tool for the job. “容器…

全能大模型GPT-4o体验和接入教程

GPT-4o体验和接入教程 前言一、原生API二、Python LangchainSpring AI总结 前言 Open AI发布了产品GPT-4o&#xff0c;o表示"omni"&#xff0c;全能的意思。 GPT-4o可以实时对音频、视觉和文本进行推理&#xff0c;响应时间平均为 320 毫秒&#xff0c;和人类之间对…

【C++篇】深度解析类与对象(上)

目录 引言 一、类的定义 1.1类定义的基本格式 1.2 成员命名规范 1.3 class与struct的区别 1.4 访问限定符 1.5 类的作用域 二、实例化 2.1 类的实例化 2.2 对象的大小与内存对齐 三、this 指针 3.1 this指针的基本用法 3.2 为什么需要this指针&#xff1f; 3.3 t…

Java毕业设计 基于SpringBoot发卡平台

Java毕业设计 基于SpringBoot发卡平台 这篇博文将介绍一个基于SpringBoot发卡平台&#xff0c;适合用于Java毕业设计。 功能介绍 首页 图片轮播 商品介绍 商品详情 提交订单 文章教程 文章详情 查询订单  查看订单卡密 客服   后台管理 登录 个人信息 修改密码 管…

成都爱尔胡建斌院长讲解年纪大眼花?小心黄斑变性!

中老年朋友觉得年龄增加后&#xff0c;眼睛出现模糊是常态&#xff0c;但是眼花不止“老花眼”一种&#xff0c;要小心的是眼底病变&#xff01; 眼花的形式有很多种&#xff0c;如果视线中间出现暗点视物变得模糊&#xff0c;很难看清周围的人脸&#xff0c;在看书看手机这种…

MATLAB(Octave)混电动力能耗评估

&#x1f3af;要点 处理电动和混动汽车能耗的后向和前向算法模型(simulink)&#xff0c;以及图形函数、后处理函数等实现。构建储能元数据信息&#xff1a;电池标称特性、电池标识符等以及静止、恒定电流和恒定电压等特征阶段。使用电流脉冲或要识别的等效电路模型类型配置阻抗…

jmeter学习(6)逻辑控制器-循环

循环执行 1、循环读取csv文件的值 2、foreach 读取变量&#xff0c;变量数字后缀有序递增&#xff0c;通过counter实现 ${__V(typeId${typeIdNum})} beansell断言 String typeIdNum vars.get("typeIdNum"); String response prev.getResponseDataAsString(); …

MAC 安装HomeBrew-亲自尝试,100%会成功

文章来自这里: https://zhuanlan.zhihu.com/p/620975942 安装指令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"执行完成后&#xff0c;输入下列命令验证 brew --version

AcWing 875:快速幂

【题目来源】https://www.acwing.com/problem/content/877/【题目描述】 给定 组 &#xff0c;对于每组数据&#xff0c;求出 的值。【输入格式】 第一行包含整数 。 接下来 行&#xff0c;每行包含三个整数 。【输出格式】 对于每组数据&#xff0c;输出一个结果&#xff0…

初阶数据结构【3】--单链表(比顺序表还好的一种数据结构!!!)

本章概述 前情回顾单链表实现单链表彩蛋时刻&#xff01;&#xff01;&#xff01; 前情回顾 咱们在上一章博客点击&#xff1a;《顺序表》的末尾&#xff0c;提出了一个问题&#xff0c;讲出了顺序表的缺点——有点浪费空间。所以&#xff0c;为了解决这个问题&#xff0c;我…

计算机网络-RSTP快速生成树基础概念

一、STP概念复习 在之前的学习中我们已经学习了STP的概念与作用。参考文章&#xff1a;计算机网络-生成树基础 STP&#xff08;Spanning Tree Protocol&#xff0c;生成树协议&#xff09; 是一种用于在局域网中消除数据链路层物理环路的协议。主要作用是防止交换机冗余链路产生…

app端文章列表查询-详细教程(上)

app端文章列表查询 一、数据库方面 有关文章的表垂直拆分成了三张表&#xff1a;文章基本信息表&#xff08;字段有文章id、文章作者、文章标题、发布时间等&#xff09;、文章配置表&#xff08;字段有文章id、文章是否可评论、文章可转发、是否已下架、是否已删除等&#x…

MySQL 基础查询

1、DISTINCT select DISTINCT EMPLOYEE_ID ,FIRST_NAME from employees 按照ID去重&#xff0c;DISTINCT的字段要放在前面&#xff0c;不会再继续在FIRST_NAME上去重判断&#xff1b; 如果需要多字段去重&#xff0c;需要用到group by&#xff0c;这个后面讲&#xff1b; …

【Fargo】11: pacing 参数不生效:同步调整采集码率

发送侧参数改变 接收测没感觉到 还是2秒收到60个不变: 果然,发送侧的参数设置没生效 发送的码率终于正确了

【C++、数据结构】二叉排序树(二叉查找树、二叉搜索树)(图解+完整代码)

目录 [⚽1.什么是二叉排序树] [&#x1f3d0;2.构建二叉排序树] [&#x1f3c0;3.二叉排序树的查找操作] [&#x1f94e;4.二叉排序树的删除] [&#x1f3b1;5.完整代码] ⚽1.什么是二叉排序树 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是…

【慕伏白教程】将 Windows11 装进口袋 -- 便携式 Windows 11 制作教程

目录 下载 Windows 11 镜像下载 Rufus开始安装 Windows 11 下载 Windows 11 镜像 打开微软 Windows 11 官方下载网站&#xff0c;找到 下载适用于 x64 设备的 Windows 11 磁盘映像 (ISO) 根据个人情况选择要下载的磁盘镜像&#xff0c;选择多版本 ISO 的话可在安装系统开始时进…

多IP连接

一.关闭防火墙 systemctl stop firewalld setenforce 0 二.挂在mnt mount /dev/sr0 /mnt 三.下载nginx dnf install nginx -y 四.启动nginx协议 systemctl start nginx 五.修改协议 vim /etc/nginx/nginx.conf 在root前加#并且下一行添加 root /www:&#xff08;浏…

基于图像拼接开题报告

选题的背景与意义 在日常生活中&#xff0c;使用普通相机获取宽视野的场景图像时&#xff0c;必须通过调节相机的焦距才可以提取完整的场景。由于相机的分辨率有限&#xff0c;拍摄场景越大&#xff0c;得到的图像分辨率就越低&#xff0c;因此只能通过缩放相机镜头减小拍摄的…

应对 .DevicData-X-XXXXXXXX 勒索病毒:防御与恢复策略

引言 随着信息技术的快速发展&#xff0c;网络安全问题愈发严峻。勒索病毒作为一种恶性网络攻击手段&#xff0c;已成为企业和个人面临的重大威胁之一。尤其是 .DevicData-X-XXXXXXXX 勒索病毒&#xff0c;其通过加密用户数据并勒索赎金&#xff0c;给受害者带来了巨大的经济损…

dolphinscheduler创建工作流及工作流中DataX的使用(简单操作)

一、在项目管理中创建项目&#xff1a;点击创建项目 用哪个用户登录的&#xff0c;所属用户就是哪个&#xff0c;直接输入项目名即可 二、点击项目&#xff0c;在项目中创建工作流&#xff0c;用DataX同步数据 按照图片的步骤依次填写完成&#xff0c;注意 图片中的第九步是写…