秒懂C++之类与对象(中)

news2024/9/21 15:40:39

fe594ea5bf754ddbb223a54d8fb1e7bc.gif

目录

一.流插入,流提取运算符

二.const成员函数

三.取地址重载

四.构造函数(列表初始化)

小测试:

五.全部代码


前排提醒:本文所参考代码仍是取用上篇文章关于日期类相关功能的实现~末尾有全部代码~

一.流插入,流提取运算符

为什么流插入cout不能对类使用呢?

因为d1是自定义类型,需要有相关的流提取运算符重载函数,而函数Print中cout是对内置类型作处理,有默认的成员函数。

如果运算符重载函数这样写,那么图中第一种写法会报错,第二种反而不会~

小细节:ostream不用加const,因为是它是流插入,肯定是会变化的。

因为双操作数的运算符是有规定顺序的,第一参数为左操作数,第二参数为右操作数。这里第一操作数给了this指针,这样肯定是不行的。

要想避免这种情况,我们只能把该函数写到全局中去,这样才能设置两个参数。

这样还有两个问题:一是关于私有成员的访问(_year等)另一个是诸如(cout<<d1<<d2)这种连续赋值得有返回值。

ostream& operator<<(ostream& out,const Date& d)
{
	out << d._year << "年" <<d._month << "月" << d._day << "日" << endl;
	return out;
}

在声明的类里面设置友元函数就可以去访问了,类外在额外放一份声明。

流提取也一样,唯一不同的是流提取是把内容放在Date里,所以这里不加const。

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;

	return in;
}

二.const成员函数

如果我们在定义时给d1加了const,那么d1的类型就会发生改变,由于实参是&d1那么类型就变为const Date* ,而在Print函数中的隐藏this指针的类型是Date*所以实参与形参之间存在权限放大问题,造成报错。

要想解决该问题这里只能让Print处的形参权限缩小,在C++规定中我们是这样处理的:使得形参与实参之间实现权限平移。

我们再重新定义对象d2可以看出,实参类型为Date* ,形参类型为const Date*,二者是一个权限缩小的过程,也可以正常进行。

const成员函数中const对象与非const对象都可以调用const成员函数,当然const成员函数也并不是能够全部应用,遇到需要修改this指针指向的函数就无法使用const成员函数(例如+=,-=),还有流插入与流提取(因为它们在全局中,没有隐藏的this指针)。

三.取地址重载

Date* Date::operator&()
{
	cout << "Date* operator&()" << endl;
	return this;
}
const Date* Date::operator&()const
{
	cout << "const Date* operator&()const" << endl;
	return this;
}

二者都是默认成员函数,写不写编译器都会默认生成的。 

同理d2其实两个重载都可以调用,只不过会优先调用最匹配的~

四.构造函数(列表初始化)

class A
	{
	public:
	    A(int a = 0)
	        :_a(a)
	    {
	        cout << "A(int a = 0)" << endl;
	    }
	private:
	    int _a;
	};

namespace bit
	{
	    class Date
	    {
	    public:
	        Date(int year, int month, int day)
	        {
	            // 函数体内初始化
	            _year = year;
	            _month = month;
	            _day = day;
	
	            //_ref = year;
	            //_n = 1;
	        }
	
	    private:
	        // 声明
	        int _year; 
	        int _month;
	        int _day;
	        int& _ref;	  
	        const int _n; 
			A _aa;
	    };
	}
int main()
{

	bit::Date d1(2023, 10, 31);

	return 0;
}

列表初始化必须存在的意义是它可以初始化在函数体内无法初始化的变量,例如const,引用,自定义类型。

对于const与引用而言,它们是必须要在定义的时候初始化。(必须得先有一个实体空间,后面才能初始化)

这里只是声明,空间只能在对象定义时才开

怎么说呢~bit::Date d1(2023, 10, 31);这里是对象整体定义房子的轮廓修建例如房子各个设施修缮的时间,程度,布局等等都没有涉及)。

而能让每个成员都知道在什么地方定义(知道修缮时间,布局)只有靠初始化列表(之所以是每个是因为有三种成员无法在函数体内初始化),除这3个成员之外的其实可以在函数体内那定义。

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟 一个放在括号中的初始值或表达式。
Date(int year, int month, int day)
				//列表初始化
				:_year(year)
				,_month(month)
				,_day(day)
				, _ref(year)
				,_n(1)
                ,_aa(10)
	        {
	            // 函数体内初始化
	            /*_year = year;
	            _month = month;
	            _day = day;*/
	
	            //_ref = year;
	            //_n = 1;
	        }

列表初始化与函数体内初始化也可以混用

 默认构造函数(全缺省,无实参,默认生成). 

在列表初始化那对内置类型年月日定义并且给了随机值(因为没有写)对自定义成员_aa则是去调用它的构造函数(如果无默认构造呢?让int a = 0变为int a——报错),不过年月日随机值在后面的函数体内初始化还是会初始化为我们所给的值。

所以针对无默认拷贝构造的自定义类型,const与引用这三者必须放在列表初始化里。

只不过混用并不是指这种特地把年月日放在函数体内初始化而不是列表初始化。

函数体内初始化还是有一些好处的,比如可以检查开辟的空间是否出错或是把内容拷贝给数组

因此我们尽量使用列表初始化,毕竟函数体内初始化处理不了自定义,const与引用。

反正说来说去就一点,对自定义类型而言如果不用或没有默认构造,那就在列表初始化那里老老实实给值。对内置类型而言,你可以选择在声明那给缺省值,也可以在列表初始化那给值,否则最终就是随机值。 

小测试:

class A
{
public:
    A(int a)
        :_a1(a)
        , _a2(_a1)
    {}

    void Print() {
        cout << _a1 << " " << _a2 << endl;
    }
private:
    int _a2;
    int _a1;
};

int main() 
{
    A aa(1);
    aa.Print();
}

最终输出结果为1 ,随机值。

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

 所以是先初始化_a2然后才是_a1。

五.全部代码

//test.cpp
//test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include "Date.h"


class A
	{
	public:
	    A(int a=0)
	        :_a(a)
	    {
	        cout << "A(int a = 0)" << endl;
	    }
	private:
	    int _a;
	};

namespace bit
	{
	    class Date
	    {
	    public:
			Date(int year, int month, int day)
				//列表初始化

				: _ref(year)
				,_n(1)
				,_year(year)
	        {
	            // 函数体内初始化
	            _year = year;
	            _month = month;
	            _day = day;
	
	            //_ref = year;
	            //_n = 1;
	        }
	
	    private:
	        // 声明
	        int _year; 
	        int _month;
	        int _day;
	        int& _ref;	  
	        const int _n; 
			A _aa;
	    };
	}
//int main()
//{
//
//	bit::Date d1(2023, 10, 31);
//
//	return 0;
//}
class A
{
public:
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}

	void Print() {
		cout << _a1 << " " << _a2 << endl;
	}
private:
	int _a2;
	int _a1;
};

int main()
{
	A aa(1);
	aa.Print();
}

 

//Date.cpp
//Date.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"

//构造初始化
Date::Date(int year = 1, int month = 1, int day = 1)
{
	_year = year;
	_month = month;
	_day = day;
	if (_year < 1 || _month < 1 || _month>12 || _day<1 || _day>GetMonthDay(_year, _month))
	{
		Print();
		cout << "日期违法" << endl;
	}
}
//打印
void Date::Print() const
{
	cout << _year << "--" << _month << "--" << _day << endl;
}
//类与类拷贝构造
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{
	static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,
   31 };
	int day = days[month];
	if (month == 2
		&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		day += 1;
	}
	return day;
}

Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-day);
	}
	//复用+
	/**this = *this + day;
	return *this;*/
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month > 12)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}


Date Date::operator+(int day)const
{
	//复用+=
	Date tmp(*this);
	tmp += day;
	return tmp;

	/*Date tmp(*this);
	tmp._day += day;
	_day += day;
	while (_day > GetMonthDay(tmp._year, tmp._month))
	{
		tmp._day -= GetMonthDay(tmp._year, tmp._month);
		tmp._month++;
		if (tmp._month > 12)
		{
			tmp._year++;
			tmp._month = 1;
		}
	}
	return tmp;*/
}

// >运算符重载
bool Date:: operator>(const Date& d)const
{
	if (_year > d._year)
	{
		return true;
	}
	else if (_year == d._year && _month > d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day > d._day)
	{
		return true;
	}
	return false;

}

// ==运算符重载
bool Date::operator==(const Date& d)const
{
	if (_year == d._year && _month == d._month && _day == d._day)
	{
		return true;
	}
	return false;
}

// !=运算符重载
bool Date::operator != (const Date& d)const
{
	return !(*this == d);
}

// >=运算符重载
bool Date::operator >= (const Date& d)const
{
	return (*this == d) || (*this > d);
}

// <运算符重载
bool Date::operator<(const Date& d)const
{
	return !(*this >= d);
}

// <=运算符重载
bool Date::operator <= (const Date& d)const
{
	return !(*this > d);
}

// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-day);
	}
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month <= 0)
		{
			_year--;
			_month = 12;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

// 后置--
Date Date::operator--(int)
{
	Date tmp(*this);
	*this -= 1;
	return tmp;
}
// 前置--
Date& Date:: operator--()
{
	*this -= 1;
	return *this;
}
// 日期-天数
Date Date::operator-(int day)const
{
	Date tmp(*this);
	tmp -= day;
	return tmp;
}

// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	int flag = 1;
	int n = 0;
	Date max = *this;
	Date min = d;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	while (max != min)
	{
		min++;
		n++;
	}
	return n * flag;
}

Date& Date::operator=(const Date& d)
{
	if (this != &d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}
}

ostream& operator<<(ostream& out,const Date& d)
{
	out << d._year << "年" <<d._month << "月" << d._day << "日" << endl;
	return out;
}

istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;

	return in;
}

Date* Date::operator&()
{
	cout << "Date* operator&()" << endl;
	return this;
}
const Date* Date::operator&()const
{
	cout << "const Date* operator&()const" << endl;
	return this;
}
void Date::operator<<(ostream& out)
{
	out << _year << "年" << _month << "月" << _day << "日" << endl;
}
//Date.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class Date
{
public:
	//构造初始化
	Date(int year, int month, int day);

	//打印
	void Print()const;

	//类与类拷贝构造
	Date(const Date& d);

	Date& operator=(const Date& d);

	//获取某年某月的天数
	int GetMonthDay(int year, int month);

	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day)const;
	// 日期-天数
	Date operator-(int day)const;
	// 日期-=天数
	Date& operator-=(int day);
	// 前置++
	Date& operator++();
	// 后置++
	Date operator++(int);
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();

	// >运算符重载
	bool operator>(const Date& d)const;
	// ==运算符重载
	bool operator==(const Date& d)const;
	// >=运算符重载
	bool operator >= (const Date& d)const;

	// <运算符重载
	bool operator <(const Date& d)const;
	// <=运算符重载
	bool operator <= (const Date& d)const;
	// !=运算符重载
	bool operator != (const Date& d)const;
	// 日期-日期 返回天数
	int operator-(const Date& d);

	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
	const Date* operator&()const;
	Date* operator&();


private:
	int _year;
	int _month;
	int _day;
};

 ostream& operator<<(ostream& out,const Date& d);
 istream& operator>>(istream& in, Date& d);

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

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

相关文章

使用Redis的SETNX命令实现分布式锁

什么是分布式锁 分布式锁是一种用于在分布式系统中控制多个节点对共享资源进行访问的机制。在分布式系统中&#xff0c;由于多个节点可能同时访问和修改同一个资源&#xff0c;因此需要一种方法来确保在任意时刻只有一个节点能够对资源进行操作&#xff0c;以避免数据不一致或…

WPF/C#:实现导航功能

前言 在WPF中使用导航功能可以使用Frame控件&#xff0c;这是比较基础的一种方法。前几天分享了wpfui中NavigationView的基本用法&#xff0c;但是如果真正在项目中使用起来&#xff0c;基础的用法是无法满足的。今天通过wpfui中的mvvm例子来说明在wpfui中如何通过依赖注入与M…

STM32智能安防系统教程

目录 引言环境准备智能安防系统基础代码实现&#xff1a;实现智能安防系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;家庭与企业安防管理问题解决方案与优化收尾与总结 1. 引言 智能安防系统通过STM32…

解决npm install(‘proxy‘ config is set properly. See: ‘npm help config‘)失败问题

摘要 重装电脑系统后&#xff0c;使用npm install初始化项目依赖失败了&#xff0c;错误提示&#xff1a;‘proxy’ config is set properly…&#xff0c;具体的错误提示如下图所示&#xff1a; 解决方案 经过报错信息查询解决办法&#xff0c;最终找到了两个比较好的方案&a…

【Charles】-雷电模拟器-抓HTTPS包

写在前面 之前的文章我们写过如何通过Charles来抓取IOS手机上的HTTPS包以及遇到的坑。说一个场景&#xff0c;如果你的手机是IOS&#xff0c;但是团队提供的APP安装包是Android&#xff0c;这种情况下你还想抓包&#xff0c;怎么办&#xff1f; 不要慌&#xff0c;我们可以安装…

宝塔面板以www用户运行composer

方式一 执行命令时指定www用户 sudo -u www composer update方式二 在网站配置中的composer选项卡中选择配置运行

c# .net core中间件,生命周期

某些模块和处理程序具有存储在 Web.config 中的配置选项。但是在 ASP.NET Core 中&#xff0c;使用新配置模型取代了 Web.config。 HTTP 模块和处理程序如何工作 官网地址&#xff1a; 将 HTTP 处理程序和模块迁移到 ASP.NET Core 中间件 | Microsoft Learn 处理程序是&#xf…

大数据之路 读书笔记 Day7 实时技术 简介及流式技术架构

回顾&#xff1a; Day6 离线数据开发之数据开发平台Day5 数据同步遇到的问题与解决方案 1. 简介 阿里巴巴在流式数据处理方面采用了多种技术和框架&#xff0c;这些技术的特点包括&#xff1a; 高可伸缩性&#xff1a; 阿里巴巴使用Apache Flink进行大规模数据处理&#xff0c…

【已解决】Django连接MySQL启动报错Did you install mysqlclient?

在终端执行python manage.py makemigrations报错问题汇总 错误1&#xff1a;已安装mysqlclient&#xff0c;提示Did you install mysqlclient? 当你看到这样的错误信息&#xff0c;表明Django尝试加载MySQLdb模块但未找到&#xff0c;因为MySQLdb已被mysqlclient替代。 【解…

如何发一篇顶会论文? 涉及3D高斯,slam,自动驾驶,三维点云等等

SLAM&3DGS 1&#xff09;SLAM/3DGS/三维点云/医疗图像/扩散模型/结构光/Transformer/CNN/Mamba/位姿估计 顶会论文指导 2&#xff09;基于环境信息的定位&#xff0c;重建与场景理解 3&#xff09;轻量级高保真Gaussian Splatting 4&#xff09;基于大模型与GS的 6D pose e…

全时守护,无死角监测:重点海域渔港视频AI智能监管方案

一、方案背景 随着海洋经济的快速发展和海洋资源的日益紧缺&#xff0c;对重点海域渔港进行有效监控和管理显得尤为重要。视频监控作为一种高效、实时的管理手段&#xff0c;已成为渔港管理中不可或缺的一部分。当前&#xff0c;我国海域面积广阔&#xff0c;渔港众多&#xf…

Axure RP移动端医院在线挂号app问诊原型图模板

医疗在线挂号问诊Axure RP原型图医院APP原形模板&#xff0c;是一款原创的医疗类APP&#xff0c;设计尺寸采用iPhone13&#xff08;375*812px&#xff09;&#xff0c;原型图上加入了仿真手机壳&#xff0c;使得预览效果更加逼真。 本套原型图主要功能有医疗常识科普、医院挂号…

分布式存储之 ceph 管理操作

一.资源池 Pool 管理 我们已经完成了 Ceph 集群的部署&#xff0c;但是我们如何向 Ceph 中存储数据呢&#xff1f;首先我们需要在 Ceph 中定义一个 Pool 资源池。Pool 是 Ceph 中存储 Object 对象抽象概念。我们可以将其理解为 Ceph 存储上划分的逻辑分区&#xff0c;Pool 由…

Springboot项目远程部署gitee仓库(docker+Jenkins+maven+git)

创建一个Springboot项目&#xff0c;勾选web将该项目创建git本地仓库&#xff0c;再创建远程仓库推送上去 创建TestController RestController RequestMapping("/test") public class TestController { GetMapping("/hello") public String sayHelloJe…

Springboot 启动时Bean的创建与注入-面试热点-springboot源码解读-xunznux

Springboot 启动时Bean的创建与注入&#xff0c;以及对应的源码解读 文章目录 Springboot 启动时Bean的创建与注入&#xff0c;以及对应的源码解读构建Web项目流程图&#xff1a;堆栈信息&#xff1a;堆栈信息简介堆栈信息源码详解1、main:10, DemoApplication (com.xun.demo)2…

OPC UA边缘计算耦合器BL205工业通信的最佳解决方案

OPC UA耦合器BL205是钡铼技术基于下一代工业互联网技术推出的分布式、可插拔、结构紧凑、可编程的IO系统&#xff0c;可直接接入SCADA、MES、MOM、ERP等IT系统&#xff0c;无缝链接OT与IT层&#xff0c;是工业互联网、工业4.0、智能制造、数字化转型解决方案中IO系统最佳方案。…

小阿轩yx-高性能内存对象缓存

小阿轩yx-高性能内存对象缓存 案例分析 案例概述 Memcached 是一款开源的高性能分布式内存对象缓存系统用于很多网站提高访问速度&#xff0c;尤其是需要频繁访问数据的大型网站是典型的 C/S 架构&#xff0c;需要构建 Memcached 服务器端与 Memcached API 客户端用 C 语言…

VisualRules-Web案例展示(一)

VisualRules单机版以其卓越的功能深受用户喜爱。现在&#xff0c;我们进一步推出了VisualRules-Web在线版本&#xff0c;让您无需安装任何软件&#xff0c;即可在任何浏览器中轻松体验VisualRules的强大功能。无论是数据分析、规则管理还是自动化决策&#xff0c;VisualRules-W…

AWS基础知识

VPC (Virtual Private Cloud): 参考&#xff1a;https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html With Amazon Virtual Private Cloud (Amazon VPC), you can launch AWS resources in a logically isolated virtual network that you’ve defined…

【音视频 | HTTP协议】HTTP协议详细介绍(HTTP方法、报文格式、报文头部字段、状态码)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…