重生c++系列之类与对象(中篇)

好的继上期,我们今天带来c++类与对象系列的继续学习。

类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员
函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

 六个默认成员函数会实现6个功能,我们先来看第一个:

构造函数

上一段代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();return 0;
}

大家在刚开始写代码的时候,比如说这里写了一个date类,我们忘记了初始化,直接调用printf函数,由于没有初始化,三个变量的值就会使三个随机数:

 这是不是就麻烦了,这个事情不仅仅是我们经常忘记,c++祖师爷也经常忘记,所以祖师爷就想给c++多个功能,自己初始化,所以祖师爷就搞了一个新的东西:构造函数

构造函数的特性:

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任
并不是开空间创建对象,而是初始化对象

其特征如下:
1. 函数名与类名相同。
2. 无返回值。 (不需要写void)
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载。 (可以有多个构造函数,多种初始化方式)
我们给上边日期类写一个构造函数试试,看看是否真的可以初始化:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public://构造函数Date(){_year = 2023;_month = 8;_day = 30;cout << "构造函数" << endl;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();return 0;
}

很好,我们可以发现该类就是调用了我们写构造函数进行了初始化日期,并且我们无需调用,省下了很多时间
现在的初始化没有传参,是规定好的,就是我们构建无数次日期类的变量,都是这个时间,如果我们想自己在外部(主函数)自己传一个日期进行初始化,该怎么办?
非常简单,再写一个带参的构造函数就可以了
上代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public://构造函数Date(){_year = 2023;_month = 8;_day = 30;cout << "构造函数" << endl;}//有参构造函数Date(int year,int month,int day){_year = year;_month = month;_day = day;cout << "有参构造函数" << endl;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023,1,1);d2.Printf();return 0;
}

可以看到,我们另外又写了一个构造函数,是有参数的构造函数,两个构造函数构成函数重载,如果我们没传参,就自动调用第一个无参构造函数,如果又传参,就按照我们自己的想法调用第二个有参构造函数进行初始化,是不是和我们前两期函数重载的知识点结合起来了!另外,大家要注意一下d2的传参数方式,很新很方便,比调用init要方便的多,这个大家记住就行了。
运行截图论证:
再回想一下我们第二期讲的内容,是不是有一个缺省参数,好好好,那么是不是可以根据这个知识点把两个构造参数合二为一
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:Date(int year=2023,int month=8,int day=30){_year = year;_month = month;_day = day;cout << "有参构造函数" << endl;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023,1,1);d2.Printf();return 0;
}

 这样不单单就简介了,还更灵活了,看不懂的同学自觉去看前两期内容

两次都是调用的这个构造函数,这就是缺省的魅力

是不是还可以这么玩:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:Date(int year=2023,int month=8,int day=30){_year = year;_month = month;_day = day;cout << "有参构造函数" << endl;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023,1,1);d2.Printf();Date d3(2023);d3.Printf();Date d4(2023, 12);d4.Printf();return 0;
}

好好好,缺省参数被我们玩坏了

刚刚我们看的是日期类的构造函数,相对来说比较简单,现在我们来进阶一下,看看栈的构造函数:
class Stack
{
public:
    Stack()
    {
        a = nullptr;
        top = capacity = 0;
    }
    void Push(int x)
    {
        if (top == capacity)
        {
            cout << capacity << "扩容" << endl;
            size_t newcapacity = capacity == 0 ? 4:capacity * 2;
            a = (int*)realloc(a, sizeof(int) * newcapacity);
            capacity = newcapacity;
        }
        a[top++] = x;
    }
private:
    int *a;
    int top;
    int capacity;
    int size;
};
众所周知,构造函数也叫默认成员函数,默认什么意思,也就是说,我们不去写构造函数,编译器也会自动生成
构造函数,也是默认成员函数,我们不写,编译器会自动生成编译生成的默认构造的特点:
1、我们不写才会生成,我们写了就不会生成了
2、内置类型的成员不会处理
3、自定义类型的成员才会处理,会去调用这个成员的构造函数
像是我们之前写的那个日期类,如果我们没写构造函数,他也不会自动生成,因为三个成员都是内置类型
一般情况下,都需要我们自己写构造函数,如果类变量都是自定义变量,可以有选择不写

析构函数

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的? 析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

析构函数的特性

析构函数是特殊的成员函数,其特征如下:

1. 析构函数名是在类名前加上字符 ~。

2. 无参数无返回值类型。

3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载

4. 对象生命周期结束时,C++编译系统系统自动调用析构函数

上代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 2023, int month = 8, int day = 30){_year = year;_month = month;_day = day;cout << "有参构造函数" << endl;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}~Date(){cout << "析构函数" << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023, 1, 1);d2.Printf();return 0;
}

看,我们写的析构函数自动被调用了 

日期类的析构函数我们看不出什么来,来试试栈的析构函数

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Stack
{
public:Stack(){cout << "构造函数" << endl;a = nullptr;top = capacity = 0;}void Push(int x){if (top == capacity){cout << capacity << "扩容" << endl;size_t newcapacity = capacity == 0 ? 4 : capacity * 2;a = (int*)realloc(a, sizeof(int) * newcapacity);capacity = newcapacity;}a[top++] = x;}~Stack(){cout << "析构函数" << endl;free(a);a = nullptr;top = capacity = 0;}
private:int* a;int top;int capacity;int size;
};
int main()
{Stack s1;return 0;
}

自动调用,无论写多少个,所以这就生下了我们很多初始化和删除的时间

拷贝构造函数

上代码:

#include<iostream>
using namespace std
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// Date(const Date& d)   // 正确写法Date(const Date& d)   // 错误写法:编译报错,会引发无穷递归{_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2(d1);return 0;
}

直接拷贝的d1给d2赋值

拷贝构造的特征:

拷贝构造函数也是特殊的成员函数,其特征如下:
1. 拷贝构造函数是构造函数的一个重载形式
2. 拷贝构造函数的参数只有一个必须是类类型对象的引用,使用传值方式编译器直接报错
因为会引发无穷递归调用。

赋值运算符重载

上代码:

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 2023, int month = 8, int day = 30){_year = year;_month = month;_day = day;cout << "有参构造函数" << endl;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}~Date(){cout << "析构函数" << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2023, 1, 1);Date d2(2023, 1, 2);d1 < d2;return 0;
}

大家看看这样比较两个日期类的变量行不行

答案是当然不行

 但是这样写

int i,j;

i<j;

这样比较,就可以,这是因为编译器知道int变量的存储模式和比较方式

那么我们可不可以让编译器也可以直接比较date

这就涉及到这个课题内容运算符重载

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:Date(int year = 2023, int month = 8, int day = 30){_year = year;_month = month;_day = day;cout << "有参构造函数" << endl;}void Printf(){cout << _year << '/' << _month << '/' << _day << endl;}~Date(){cout << "析构函数" << endl;}//private:int _year;int _month;int _day;
};
bool operator<(const Date& x1, const Date& x2)
{if (x1._year < x2._year){return true;}else if (x1._year == x2._year && x1._month < x2._month){return true;}else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day){return true;}else{return false;}
}
int main()
{Date d1(2023, 1, 1);Date d2(2023, 1, 2);cout<<(d1 < d2)<<endl;return 0;
}

有函数重载,就有运算符重载,上边就是使用规则,大家记住就行了

那有<运算符,就有<=,>,>=,=,+,-,+=,-=

博主在这里一一实现了

class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}bool operator<(const Date& d){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;}else{return false;}}bool operator==(const Date& d){return _year == d._year&& _month == d._month&& _day == d._day;}// d1 <= d2bool operator<=(const Date& d){return *this < d || *this == d;}bool operator>(const Date& d){return !(*this <= d);}bool operator>=(const Date& d){return !(*this < d);}bool operator!=(const Date& d){return !(*this == d);}int GetMonthDay(int year, int month){int monthArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))){return 29;}return monthArray[month];}Date& operator+=(int day){_day += day;while (_day > GetMonthDay(_year, _month)){// 月进位_day -= GetMonthDay(_year, _month);++_month;// 月满了if (_month == 13){++_year;_month = 1;}}return *this;}Date operator+(int day){Date tmp(*this);tmp += day;return tmp;//tmp._day += day;//while (tmp._day > GetMonthDay(tmp._year, tmp._month))//{//	// 月进位//	tmp._day -= GetMonthDay(tmp._year, tmp._month);//	++_month;//	// 月满了//	if (tmp._month == 13)//	{//		++tmp._year;//		tmp._month = 1;//	}//}//return tmp;}private:// 内置类型int _year;int _month;int _day;
};

 

关于日期各种加减乘除运算的逻辑实现是没有任何难度的,就是年完月,月完日,进位加

大家要理解的是重载的操作

注意:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this
.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出
现。

好的类和对象的中篇就到这里,对于默认成岩函数基本就接好玩了,期待三连

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

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

相关文章

pyqt5-快捷键QShortcut

import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *""" 下面示例揭示了&#xff0c;当关键字绑定的控件出现的时候&#xff0c;快捷键才管用&#xff0c; 绑定的控件没有出现的时候快捷键无效 """…

vscode使用anaconda自带的python环境在终端运行时报错

目录 具体报错内容官方翻译报错讲人话解决方法 具体报错内容 CommandNotFoundError: Your shell has not been properly configured to use conda activate. If your shell is Bash or a Bourne variant, enable conda for the current user with$ echo ". E:\Anaconda/e…

无涯教程-Android - Activity

Activity代表具有用户界面的单个屏幕&#xff0c;就像Java的窗口或框架一样。Android Activity 是ContextThemeWrapper类的子类。 如果您使用过C&#xff0c;C或Java编程语言&#xff0c;那么您一定已经看到您的程序从 main()函数开始。与之非常相似&#xff0c;Android系统以 …

MySQL日期格式及日期函数实践

目录 日期格式 日期函数 CURDATE()和CURRENT_DATE()CURTIME()和CURRENT_TIME()NOW()和CURRENT_TIMESTAMP()DATE_FORMAT()DATE_ADD()和DATE_SUB()DATEDIFF()DATE()DAYNAME()和MONTHNAME() 1. 日期格式 在MySQL中&#xff0c;日期可以使用多种格式进行存储和表示。常见的日期格式…

m3u8 blob视频免费下载

F12点开找到这个视频url最后是.m3u8结尾 http://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html 在上边的网址转Mp4下载即可

Flutter可执行屏幕动画的AnimateView

1.让动画使用起来就像使用widget。 2.可自定义动画。 3.内置平移动画。 演示&#xff1a; 代码: import dart:math; import package:flutter/cupertino.dart;class AnimateView extends StatefulWidget {///子Widgetfinal Widget child;///动画自定义final IAnimate? anim…

HTML-常见标签、HTML5新特性

HTML 软件架构 1.C/S架构 (1) C/S架构即Client/Server&#xff08;客户机/服务器&#xff09;结构。 (2) C/S 架构特点 ​ C/S结构在技术上很成熟&#xff0c;它的主要特点是交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。但是该结构的程序是…

ssm会议管理系统源码和论文

ssm会议管理系统源码和论文087 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&…

玩转 PI 系列-看起来像服务器的 ARM 开发板矩阵-Firefly Cluster Server

前言 基于我个人的工作内容和兴趣&#xff0c;想要在家里搞一套服务器集群&#xff0c;用于容器/K8s 等方案的测试验证。 考虑过使用二手服务器&#xff0c;比如 Dell R730, 还搞了一套配置清单&#xff0c;如下&#xff1a; Dell R7303.5 尺寸规格硬盘CPU: 2686v4*2 内存&a…

深入浅出SSD:固态存储核心技术、原理与实战(文末赠书)

名字&#xff1a;阿玥的小东东 学习&#xff1a;Python、C/C 主页链接&#xff1a;阿玥的小东东的博客_CSDN博客-python&&c高级知识,过年必备,C/C知识讲解领域博主 目录 内容简介 作者简介 使用Python做一个计算器 本期赠书 近年来国家大力支持半导体行业&#xff0…

MySQL----索引

一、索引的概念 索引是一个排序的列表&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于c语言的链表通过指针指向数据记录的内存地址&#xff09;。使用索引后可以不用扫描全表来定位某行的数据&#xff0c;而是先通过索引表找到该…

Mysql--技术文档--MVCC(Multi-Version Concurrency Control | 多版本并发控制)

MVCC到底是什么 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是一种并发控制机制&#xff0c;用于解决并发访问数据库时的数据一致性和隔离性问题。MVCC允许多个事务同时读取数据库的同一数据&#xff0c;而不会相互干扰或导致冲突。 在传统的并发控制机制中…

基于Spring实现博客项目

访问地址:用户登录 代码获取:基于Spring实现博客项目: Spring项目写博客项目 一.项目开发 1.项目开发阶段 需求评审,需求分析项目设计(接口设计,DB设计等&#xff0c;比较大的需求,需要设计流程图&#xff0c;用例图,UML, model中的字段)开发&#xff0b;自测提测(提交测试…

DOM破坏绕过XSSfilter例题

目录 一、什么是DOM破坏 二、例题1 三、多层关系 1.Collection集合方式 2.标签关系 3.三层标签如何获取 四、例题2 五、例题3 1.代码审计 2.payload分析 一、什么是DOM破坏 DOM破坏&#xff08;DOM Clobbering&#xff09;指的是对网页上的DOM结构进行不当的修改&am…

计算机网络MTU和MSS的区别

在计算机网络中&#xff0c;MTU代表最大传输单元&#xff08;Maximum Transmission Unit&#xff09;&#xff0c;而MSS代表最大分节大小&#xff08;Maximum Segment Size&#xff09;。 1.MTU&#xff08;最大传输单元&#xff09;&#xff1a; MTU是指在网络通信中&#x…

网络服务第二次作业

[rootlocalhost ~]# vim /etc/httpd/conf.d/vhosts.conf <Virtualhost 192.168.101.200:80> #虚拟主机IP及端口 DocumentRoot /www/openlab #网页文件存放目录 ServerName www.openlab.com #服务器域名 </VirtualHost> …

易云维®FMCS厂务系统创造工厂全新的“数字低碳智能”应用场景

近年来&#xff0c;新一代信息技术的高速发展为传统工业与制造业领域带来了新的机遇。信息技术加持下的制造技术发展出了新的生产方式、产业形态与管理模式。通过搭建FMCS厂务系统进行数字化转型来实现数据互联互通与业务高效协同&#xff0c;助力企业向安全、绿色、节能、高效…

上海港股通开通条件是什么?港股通交易佣金最低多少?

上海港股通权限开通条件有&#xff1a; 1、申请权限开通前20个交易日证券账户日均资产不低于50万元; 2、进行港股知识测试&#xff0c;且测试分数不低于80分; 3、风险承受能力等级需要匹配&#xff0c;无投资经验期限的门槛 港股通的股票范围是香港联合交易所恒生综合大型股…

MATLAB图论合集(二)计算最小生成树

今天来介绍第二部分&#xff0c;图论中非常重要的知识点——最小生成树。作为数据结构的理论知识&#xff0c;Prim算法和克鲁斯卡尔算法的思想此处博主不详细介绍&#xff0c;建议在阅读本帖前熟练掌握。 对于无向带权图&#xff0c;在MATLAB中可以直接以邻接矩阵的方式创建出来…

Flutter实现StackView

1.让界面之间可以嵌套且执行动画。 2.界面的添加遵循先进后出原则。 3.需要使用AnimateView&#xff0c;请看我上一篇博客。 演示&#xff1a; 代码&#xff1a; Stack: import package:flutter/cupertino.dart;///栈&#xff0c;先进后出 class KqWidgetStack {final Lis…