类的默认成员函数

在这里插入图片描述

构造函数

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

当上段代码中的d1忘记初始化时,只是构造函数就起了至关重要的作用

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

构造函数的特征:

  • 函数名与类名相同。
  • 无返回值。
  • 对象实例化时编译器自动调用对应的构造函数。
  • 构造函数可以重载(提供多种初始化的方式)。

在这里插入图片描述

在这里插入图片描述
如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数一旦用户显式定义编译器将不再生成
在这里插入图片描述 没有定义构造函数,对象也可以创建成功,因此此处调用的是编译器生成的默认构造函数

总结:
不写构造函数,编译器默认生成构造函数
编译器默认生成的构造函数:
1.内置类型不会初始化
2.自定义类型它会调用它的无参构造函数进行初始化在这里插入图片描述

上方的代码(c++98)的语法有些繁琐,而在c++11中可以优化

在这里插入图片描述
注:这里的成员变量只是定义,不是初始化,就像函数缺省参数一样,给的是缺省值。

在这里插入图片描述
注:无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数。

默认构造函数可以理解为不传参就可以调用的函数

在这里插入图片描述
注:成员变量的命名风格一般都是加个前缀或者后缀标识区分就行。

析构函数

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

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

在这里插入图片描述

注:上方的代码中Data类中的析构函数可以不写;但Stack中的析构函数必须写

在这里插入图片描述
注:
析构函数跟构造函数类似,编译器默认生成的析构函数:
1.内置类型成员不处理
2.自定义类型成员会去调用自身的析构函数

拷贝构造函数

构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用.
拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。

在这里插入图片描述
拷贝函数中的参数必须是引用传参或指针,不然会造成死递归
注:
在这里插入图片描述

如果类中没写拷贝构造,编译器会默认生成拷贝构造函数,与构造函数和析构函数不同:
1.内置类型,字节序的浅拷贝(按字节序的拷贝)
2.自定义类型,会去调用它的的拷贝构造函数

在这里插入图片描述
注:编译器默认生成拷贝构造函数并不能解决所有问题,像Stack这样的类,编译器默认生成拷贝构造完成的就是浅拷贝。解决方法:实现深拷贝的拷贝构造函数。

若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝。

赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数:operator 运算符
参数:操作符的操作数有几个就有几个参数,参数类型你要操作的类型对象
返回值:看运算符运算后的返回值是什么

在这里插入图片描述

总结:

  • 运算符默认都是给内置类型变量用的
  • 自定义类型的变量想用这些操作符,就得自己进行运算符重载
  • 运算符重载的意思是自己去写一个函数定义实现这里的运算符行为
  • 运算符号重载写成全局的可以,但是面临访问私有成员变量的问题

注:

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

在这里插入图片描述

按正常运算符重载无法区分前置++和后置++,为了区分,这里就做了一个特殊处理,给后置++增加int参数,这样就构成了函数重载

赋值运算符重载

赋值运算符主要有四点:

  1. 参数类型
  2. 返回值
  3. 检测是否自己给自己赋值
  4. 返回*this
  5. 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。

在这里插入图片描述

在这里插入图片描述

如果自己不写,编译器会默认生成赋值重载,跟拷贝构造类似,内置类型成员会完成值拷贝,自定义类型成员会调用它的赋值重载
原则上:编译器默认生成的能完成自己要的功能就可以不写,不能完成就需要我们自己写一个.。
实现数据结构类,基本都要自己写这几个成员函数(构造函数、析构函数、拷贝函数、赋值重载都需要自己写,默认生成的都有问题,不能用)

总结:
常用短小函数,直接在类里面定义,他们默认就是inline
C++为了增强程序的可读性,提出运算符重载,并且让我们可以实现运算符重载函数,控制这个运算符行为
一个类到底要重载哪些运算符,并且要考虑重载了这个运算符有没有意义
运算符重载和函数重载,都用了重载这个词,但是他们之前没有关联

取地址及const取地址操作符重载

class Date
{ 
public :
 Date* operator&()//取地址操作符重载
 {
 return this ;
 }
 
 const Date* operator&()const//const取地址操作符重载
 {
 return this ;
 }
private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};

不想让别人获取到地址信息

class Date
{ 
public :
 Date* operator&()//取地址操作符重载
 {
 return nullptr ;
 }
 
 const Date* operator&()const//const取地址操作符重载
 {
 return nullptr ;
 }
private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如不想让别人获取到指定的内容。

练习(类的默认成员函数)

Date.h

#pragma once
#include<iostream>
#include<assert.h>

using namespace std;
class Date
{
public:
	int GetMonthDay(int year, int month)
	{
		static int date[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 date[month];
	}
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
		if (_year < 0 || _month < 1 || _month>12 || _day<=0 || _day>GetMonthDay(_year, _month))
		{
			cout << this->_year << "/" << this->_month << "/" << this->_day;
			cout << "非法日期" << endl;
		}
	}
	void print()const
	{
		cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
	}
	Date& operator += (int day);
	Date operator +(int day)const;
	Date& operator -=(int day);
	Date operator -(int day)const;
	Date& operator ++();
	Date operator ++(int);
	Date& operator --();
	Date operator --(int);
	int operator-(const Date& d)const;
	bool 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;
		else
			return false;
	}
	bool operator >=(const Date& d)const
	{
		return *this > d || *this == d;
	}
	bool operator <(const Date& d)const
	{
		return !(*this >= d);
	}
	bool operator <=(const Date& d)const
	{
		return *this < d || *this == d;
	}
	bool operator ==(const Date& d)const
	{
		return _day == d._day && _month == d._month && _year == d._year;
	}
	bool operator !=(const Date& d)const
	{
		return !(*this == d);
	}
	Date* operator &()
	{
		return this;
	}
	const Date* operator &()const
	{
		return this;
	}
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month > 12)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}
Date Date::operator +(int day)const
{
	Date tmp(*this);
	tmp += day;
	return tmp;
}


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

Date& Date::operator ++()
{
	return *this += 1;
}
Date Date::operator ++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}
Date& Date::operator --()
{
	return *this -= 1;
}
Date Date::operator --(int)
{
	Date tmp(*this);
	*this -= 1;
	return tmp;
}
int Date::operator-(const Date& d)const
{
	Date max(*this);
	Date min(d);
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int m = 0;
	while (max != min)
	{
		min++;
		m++;
	}
	return m * flag;

}

  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值