目录
1. 类的6个默认成员函数
1.1 构造函数:初始化。
1.2 析构函数:清理
1.3 拷贝构造函数:使用同类对象初始化创建对象。
1.4 赋值运算符的重载:把一个对象赋值给另外一个对象。
1.4 取地址重载:普通对象和const对象取地址。
1.5 针对我们丕写编译默认生成的总结:
① 构造和析构的特性是类似,我们不写,编译器内置类型不处理,自定义类型调用它的构造和析构处理。
② 拷贝构造和赋值重载特性是类似的,内置类型会完成浅拷贝,自定义类型会调用他们的拷贝构造和赋值重载。
① 构造和析构的特性是类似,我们不写,编译器内置类型不处理,自定义类型调用它的构造和析构处理。
② 拷贝构造和赋值重载特性是类似的,内置类型会完成浅拷贝,自定义类型会调用他们的拷贝构造和赋值重载。
2. 构造函数
2.1构造函数:
是一个特殊的成员函数,名字与类名相同
,
创建类类型对象时由编译器自动调用
,保证每个数据成员
都有 一个合适的初始值,并且
在对象的生命周期内只调用一次
。
2.2构造函数是特殊的成员函数
,需要注意的是,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主
要任务
并不是开空间创建对象,而是初始化对象
。
2.3特征:
函数名与类名相同。
无返回值。
对象实例化时编译器自动调用对应的构造函数。
构造函数可以重载。
2.4 默认构造函数:不用参数就可以调用的构造函数。
①我们不写,编译器自动生成的。
②我们自己写的无参的。
③我们自己写的全缺省。
2.5 例
//类里面我们什么函数都不写的时候,编译器会自动生成六个成员函数,这六个函数就叫默认成员函数。
//1、构造函数->对象的初始化。
//
class Date
{
public:
//构造函数,函数名与类名相同,需要我们自己写。
//在对象实例化的时候自动调用,保证对象一定会初始化。
//全缺省
Date(int year=2022, int month=6, int day=26)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 6, 25);
d1.print();
Date d2;
d2.print();
return 0;
}
3. 析构函数
3.1 概念:
析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而
对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
3.2 特性:
析构函数
是特殊的成员函数。
1.
析构函数名是在类名前加上字符
~
。
2.
无参数无返回值。
3.
一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4.
对象生命周期结束时,
C++
编译系统系统自动调用析构函数。
3.3 示例
class Date
{
public:
Date(int capacity = 4)
{
_a = (int*)malloc(sizeof(int) * capacity);
_capacity = capacity;
_size = 0;
}
void push(int x)
{
;
}
//析构函数
~Date()
{
//资源的清理。
free(_a);
_a = nullptr;
_size = _capacity = 0;
}
private:
int* _a;
int _size;
int _capacity;
};
int main()
{
//因为对象是定义在函数中的,而函数调用会建立栈帧,栈帧中的对象构造和析构也要遵循先进后出原则。
//d1 先构造 d2后构造,d2 先析构 d1 后析构。
Date d1;
d1.push(1);
d1.push(2);
d1.push(3);
Date d2;
d2.push(1);
d2.push(2);
d2.push(3);
return 0;
}
4. 拷贝构造函数
4.1 概念:
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰), 在用已存在的类类型对象创建新对象时由编译器自动调用。
4.2 拷贝构造函数也是特殊的成员函数,其特征如下:
①
拷贝构造函数
是构造函数的一个重载形式
。
②
拷贝构造函数的
参数只有一个
且
必须使用引用传参
,使用
传值方式会引发无穷递归调用。
③
若未显示定义,系统生成默认的拷贝构造函数。
默认的拷贝构造函数对象按内存存储按字节序完成拷
贝,这种拷贝我们叫做浅拷贝,或者值拷贝。
4.3 示例
//拷贝构造函数--拷贝初始化
class Date
{
public:
//构造函数
Date(int year = 2022, int month = 6, int day = 26)
{
_year = year;
_month = month;
_day = day;
}
//析构函数
~Date()
{
//资源的清理。
}
//拷贝构造函数
//必须传引用传参,不然会发生无穷递归。
//是默认成员函数,我们不写编译器会自动生成拷贝构造函数。
//这个拷贝构造对内置类型会完成浅拷贝,或者值拷贝。
//像Stack这样的类不能是浅拷贝。需要深拷贝。如果浅拷贝,会发现生析构两次的问题。
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 6, 25);
Date d2(d1);
return 0;
}
5. 赋值操作符重载
5.1 运算符重载
① ‘ .* ’、‘ :: ’、‘ sizeof ’、‘ ?: ’、‘ . ’ 这五个运算符不能重载。
② C++
为了增强代码的可读性引入了运算符重载
,
运算符重载是具有特殊函数名的函数
,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。函数名字为:关键字operator
后面接需要重载的运算符符号
。函数原型:返回值类型
operator
操作符
(
参数列表
)
5.2 示例
class Date
{
public:
//构造函数
Date(int year=2022, int month=6, int day=26)
{
_year = year;
_month = month;
_day = day;
}
//析构函数
~Date()
{
//资源的清理。
//cout << "~Date" << endl;
}
//运算符重载
//当运算符有两个操作数时,第一个操作数是左操作数,第二个操作数是右操作数。
bool operator==(Date x)
{
return _year == x._year\
&& _month == x._month\
&& _day == x._day;
}
bool operator<(Date x)
{
if (_year < x._year)
{
return true;
}
else if (_year == x._year)
{
if (_month < x._month)
{
return true;
}
else if (_month == x._month)
{
if (_day < x._day)
return true;
}
}
return false;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 6, 25);
Date d2(2022, 6, 26);
//内置类型语言层面就支持运算符。
//自定义类型默认不支持。C++可以用运算符重载,来让类对象支持某个运算符。
cout<<(d1 == d2)<<endl;
cout << (d1 < d2) << endl;
return 0;
}
5.3 赋值运算符重载
示例:
//赋值运算符重载
class Date
{
public:
//构造函数
Date(int year=2020, int month=1, int day=11)
{
_year = year;
_month = month;
_day = day;
}
//析构函数
~Date()
{
//资源的清理。
//cout << "~Date" << endl;
}
//运算符重载
//当运算符有两个操作数时,第一个操作数是左操作数,第二个操作数是右操作数。
//写成成员函数省略掉一个操作数。因为隐含一个this
//bool operator==(Date* this,const Date& x)
bool operator==(const Date& x)
{
return _year == x._year\
&& _month == x._month\
&& _day == x._day;
}
bool operator<(const Date& x)
{
if (_year < x._year)
{
return true;
}
else if (_year == x._year)
{
if (_month < x._month)
{
return true;
}
else if (_month == x._month)
{
if (_day < x._day)
return true;
}
}
return false;
}
//赋值运算符重载
Date& operator=(const Date& x)
{
if (this != &x)//不是自己给自己赋值,才需要拷贝。
{
_year = x._year;
_month = x._month;
_day = x._day;
return *this;
}
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 6, 25);
Date d2(2022, 6, 26);
Date d3;
d1.print();
d2.print();
d3.print();
//内置类型语言层面就支持运算符。
//自定义类型默认不支持。C++可以用运算符重载,来让类对象支持某个运算符。
d3= d2 = d1;
d2.print();
d3.print();
return 0;
}
6. 日期类的实现
6.1 Date.cpp
#include"date.h"
inline int GetMonthDay(int year, int month)
{
//存储平年每月天数
static int DayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30 };
int day = DayArray[month];
if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
day=29;
}
return day;
}
//构造函数
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
//检查日期的合法性
if (year>=0 && month>0 && month<13 && day<= GetMonthDay(year,month) && day>0)
{
cout << "合法日期" << endl;
cout << year << "年" << month << "月" << day << "日" << endl;
}
else
{
cout << "非法日期" << endl;
cout << year << "年" << month << "月" << day << "日" << endl;
}
}
void Date::print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
//析构、拷贝构造、赋值重载,可以不写,默认生成的就够用了
//像Stack这样的才需要自己写。
Date& Date:: operator+=(int day)
{
if (day < 0)
{
*this -= -day;
}
else
{
_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)
{
Date ret(*this);
//复用+=
ret += day;
return ret;
}
Date& Date::operator-=(int day)
{
if (day < 0)
{
*this += -day;
}
else
{
_day -= day;
while (_day <= 0)
{
--_month;
if (_month <= 0)
{
_month = 12;
--_year;
}
_day += GetMonthDay(_year, _month);
}
}
return *this;
}
Date Date:: operator-(int day)
{
Date ret(*this);
//复用-=
ret -= day;
return ret;
}
Date& Date::operator++()
{
*this += 1;
return *this;
}
Date Date::operator++(int)
{
Date tem(*this);
*this += 1;
return tem;
}
Date& Date::operator--()
{
*this -= 1;
return *this;
}
Date Date::operator--(int)
{
Date tem(*this);
*this -= 1;
return tem;
}
bool Date::operator<(const Date& d)
{
if (_year < d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month < d._month)
{
return true;
}
else if (_month == d._month)
{
if (_day < d._day)
{
return true;
}
}
}
return false;
}
bool Date::operator==(const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator<=(const Date& d)
{
return *this < d || *this == d;
}
bool Date::operator>(const Date& d)
{
return !(*this <= d);
}
bool Date::operator>=(const Date& d)
{
return *this > d || *this == d;
}
bool Date::operator!=(const Date& d)
{
return !(*this==d);
}
int Date::operator-(const Date& d)
{
Date max = *this;
Date min = d;
int flag = 1;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (max != min)
{
min++;
n++;
}
return n*flag;
}
6.2 Date.h
#pragma once
#include<iostream>
#include<assert.h>
using std::cout;
using std::cin;
using std::endl;
class Date
{
public:
//构造函数
Date(int year = 2020, int month = 1, int day = 11);
void print();
//析构、拷贝构造、赋值重载,可以不写,默认生成的就够用了
//像Stack这样的才需要自己写。
Date& operator+=(int day);
Date operator+(int day);
Date& operator-=(int day);
Date operator-(int day);
//++d->d.operator++(&d)
//d++->d.operator++(&d,0)
//int 参数不需要给实参,因为没用,它的作用是为了跟前置++构成函数重载。
Date& operator++();
Date operator++(int);
Date& operator--();
Date operator--(int);
bool operator<(const Date& d);
bool operator>(const Date& d);
bool operator<=(const Date& d);
bool operator>=(const Date& d);
bool operator==(const Date& d);
bool operator!=(const Date& d);
int operator-(const Date& d);
private:
int _year;
int _month;
int _day;
};
6.3 test.c
#include"date.h"
int main()
{
Date d1(2022,6,26);
d1.print();
Date d2(2022,9,26);
d2.print();
d1 += 26;
//d1 -= -26;
//d1.print();
Date d5=d1+(-26);
//d1 += -26;
//d1.print();
Date d2(2022, 2, 28);//非法日期的测试
//Date retd = --d1;
//retd.print();
//retd=d1--;
//retd.print();
//d1.print();
cout << (d2 - d1) << endl;
cout << (d1 - d2) << endl;
return 0;
}
7. const成员函数
7.1
将
const
修饰的类成员函数称之为
const
成员函数
,
const
修饰类成员函数,实际修饰该成员函数
隐含的
this
指针
,表明在该成员函数中
不能对类的任何成员进行修改。
7.2
void print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
........
Date d1(2022, 6, 25);
d1.print(); //权限缩小
const Date d2;
d2.print();
8. 取地址及const取地址操作符重载
8.1 基本用不到。了解他俩是默认成员函数就行。