目录
值得收藏
类的6个默认成员函数
一、构造函数
1.概念
//定义了一个类--Date
class Date
{
//公有
public:
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Display()
{
cout <<_year<< "-" <<_month << "-"<< _day <<endl;
}
//私有
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;//实例化出一个对象,d1
d1.SetDate(2018,5,1);//手动初始化第一次
d1.Display();
Date d2;//实例化出一个对象,d2
d2.SetDate(2018,7,1);//手动初始化第二次
d2.Display();
return 0;
}
2.构造函数的特性
定义如下:
/*构造函数*/
class Date
{
public:
//以下是自己创建的两个构造函数,分别为无参的和带参的
Date()//函数名和类名相同,无返回值---无参调用
{
_year = 0;
_month = 1;
_day = 5;
}
Date(int year, int month, int day)//函数名和类名相同,无返回值---带参调用
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;//自动调用无参的构造函数
Date d2(2022, 1, 5);//自动调用带参的构造函数
// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
Date d3();
return 0;
}
Date()
{
_year = 0;
_month = 1;
_day = 5;
}
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//利用缺省将上面的代码转换为下面的代码
Date(int year = 0, int month = 1, int day = 5)
{
_year = year;
_month = month;
_day = day;
}
3. 显示定义与未显示定义构造函数
/*如果没有显示定义构造函数,会发生什么情况呢*/
class Date
{
public:
/*
未显示定义构造函数
*/
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
return 0;
}
class A
{
public:
A()
{
cout << " A()" << endl;
_a = 0;
}
/*A(int a )
{
cout << " A()" << endl;
_a = a;
}*/
private:
int _a;
};
class Date
{
public:
/*
未显示定义构造函数
*/
private:
//内置类型
int _year;
int _month;
int _day;
//自定义类型
A _aa;
};
int main()
{
Date d1;
return 0;
}
二、析构函数
1.概念
2.析构函数的特性
定义如下:
class Data
{
public:
//构造函数
Data(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//析构函数
~Data()
{
cout << '1' << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data d1;
Data d2(2022, 1, 15);
return 0;
}
class Data
{
public:
Data(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
~Data()
{
cout << "~Data()" << endl;
}
private:
int _year;
int _month;
int _day;
};
class Stack
{
public:
Stack(int capacity = 4)
{
_a = (int*)malloc(sizeof(int));
if (_a == nullptr)
{
cout << "malloc fail\n" << endl;
exit(-1);
}
_top = 0;
_capacity = capacity;
}
//如果我们不写析构函数和构造类函数类似
//对于内置类型成员变量不作处理
//对于自定义类型成员变量会去调用它的析构函数
~Stack()
{
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
int* _a;
size_t _top;
size_t _capacity;
};
class MyQueue
{
public:
private:
Stack pushST;
Stack popST;
};
int main()
{
Data d1;
Data d2(2022, 1, 15);
Stack s1;
Stack s2(20);
/*先析构s2->s1->d2->d1*/
MyQueue mq;
return 0;
}
三、拷贝构造函数
1.概念
2.拷贝构造函数的特性
定义如下:
class Date
{
public:
/*构造函数*/
Date(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
/*拷贝构造函数*/
Date(const Data& d)
{
//加const为了防止写成 d._year = _year;
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 1, 15);
//拷贝复制
Date d2(d1);//调用拷贝构造---自定义类型用一个同类型的对象初始化我,就是拷贝构造
return 0;
}
3.拷贝构造的注意点
class Stack
{
public:
//构造函数
Stack(int capacity = 4)
{
_a = (int*)malloc(sizeof(int));
if (_a == nullptr)
{
cout << "malloc fail\n" << endl;
exit(-1);
}
_top = 0;
_capacity = capacity;
}
//拷贝构造函数
/*
编译器默认生成
*/
//析构函数
~Stack()
{
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
int* _a;
size_t _top;
size_t _capacity;
};
int main()
{
/*直接崩溃*/
//导致他们指向的空间被析构两次,导致程序崩溃
Stack st1(10);
Stack st2(st1);
return 0;
}
四、赋值运算符重载
1.运算符重载
1.概念
class Data
{
public:
Data(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//private:
int _year;
int _month;
int _day;
};
int main()
{
Data d1(2022, 1, 16);
Data d2(2022, 1, 31);
int ret = d1._day > d2._day;
cout << ret << endl;
//d1 > d2;报错
return 0;
}
2.如何定义及使用
/*运算符重载*/
class Data
{
public:
Data(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//private:
int _year;
int _month;
int _day;
};
/*****类外定义******/
//函数名 operator操作符
//返回类型:看操作符运算后返回值是什么
//参数:操作符有几个操作数,他就有几个参数
bool operator>(const Data& d1, const Data& d2)
{
if (d1._year > d2._year)
{
return true;
}
else if (d1._year == d2._year && d1._month > d2._month)
{
return true;
}
else if (d1._year == d2._year && d1._month == d2._month && d1._day > d2._day)
{
return true;
}
else
{
return false;
}
}
int main()
{
Data d1(2022, 1, 16);
Data d2(2022, 1, 31);
//默认情况下,C++是不支持自定义类型对象使用运算符
d1 > d2;//编译器看到这个就会将其转换为operator>(d1,d2),就像函数调用一样
cout << (d1 > d2) << endl;
cout << operator>(d1, d2) << endl;
return 0;
}
class Date
{
public:
Date(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//bool operator>(const Date& d1, const Date& d2)
//按照这样去写,是错误的,操作数过多,因为隐含了一个this指针
//d1.operator > (d2); bool operator>(const Date* this, const Date& d2)
//d1就传给了this,d2就传给了d2
bool operator>(const Date& d2)
{
if (_year > d2._year)
{
return true;
}
else if (_year == d2._year && _month > d2._month)
{
return true;
}
else if (_year == d2._year && _month == d2._month && _day > d2._day)
{
return true;
}
else
{
return false;
}
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 1, 16);
Date d2(2022, 1, 31);
d1 > d2;//先去类看有没有这个运算符,没有去全局找 运算符重载一般重载为成员函数,为了解决访问私有变量的问题
//d1.operator > (d2);类里面转换为这样
return 0;
}
2.赋值运算符重载
1.概念
class Date
{
public:
//构造函数
Date(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//拷贝构造
Date(const Date& d)
{
cout << " 11111 " << endl;
}
//赋值运算符重载
//d1 = d3;
Date operator=(const Date& d)
{
//防止有人d1=d1
//极端情况下自己给自己赋值,判断一下地址就直接跳过了
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 1, 16);
Date d2(2022, 1, 31);
Date d3(2022, 2, 26);
//一个已经存在的对象拷贝初始化一个马上创建实例化的对象
Date d4(d1);//拷贝构造
Date d5 = d1;
//两个已经存在的对象,之间进行赋值拷贝
d2 = d1 = d3;
//d1.operator=(d3);
//d2.operator=(d1.operator=(d3));
return 0;
}
五、日期类实现
1. 日期类的定义
class Date
{
public:
//构造函数
Date(int year = 1, int month = 1, int day = 1);
//打印
void Print() const;
// 获取某年某月的天数
int GetMonthDay(int year, int month);
// >运算符重载
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);
// 日期 += 天数
Date& operator+=(int day);
// 日期 + 天数
Date operator+(int day);
// 日期 -= 天数
Date& operator-=(int day);
// 日期 - 天数
Date operator-(int day);
// 前置++
Date& operator++();
// 后置++; 后置为了跟前置++,进行区分,增加了一个参数占位,跟前置++,构成重载
Date operator++(int);
// 前置--
Date& operator--();
// 后置--
Date operator--(int);
// 日期-日期 返回天数
int operator-(const Date& d);
//获取某天是周几
void PrintWeekDay();
private:
int _year;
int _month;
int _day;
};
2.日期类的接口实现
①日期类的构造函数
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)const
{
static int monthDayArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int day = monthDayArray[month];//获取每个月的天数
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
day += 1;//如果是二月并且是闰年,天数就加+1
}
return day;
}
//构造函数
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
if (!(_year >= 0
&& (month > 0 && month < 13)
&& (day > 0 && day <= GetMonthDay(year, month))))
{
//不满足年月日的条件,就是非法的
cout << "非法日期->";
Print();
}
}
//打印
void Date::Print()const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
②日期类比较运算符重载
// >运算符重载
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;
}
else
{
return false;
}
}
// ==运算符重载
bool Date::operator==(const Date& d)const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
// <运算符重载
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 > GetMonthDay(_year, _month))
{
//凑满本月天数,月进位1
_day -= GetMonthDay(_year, _month);
++_month;
//如果月进位到13时,年进位,月置1
if (_month == 13)
{
_month = 1;
_year++;
}
}
return *this;
}
// 日期 + 天数
Date Date::operator+(int day)const
{
Date ret(*this);
//ret.operator+=(day);
ret += day;
return ret;
}
// 日期 -= 天数
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;//如果传过来的天数是负数,实际上就是调用+=,把天数变为正数
}
_day -= day;//先将天数减去
while (_day <= 0)
{
//向月借位
--_month;
//当月借完后,就要向年借位,并把月置1
if (_month == 0)
{
--_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++()
{
*this += 1;
return *this;
}
// 后置++
Date Date::operator++(int)
{
Date ret(*this);
//Date ret = *this;
*this += 1;
return ret;
}
// 前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
// 后置--
Date Date::operator--(int)
{
Date ret(*this);
//Date ret = *this;
*this -= 1;
return ret;
}
⑤日期 - 日期及获取某天是周几
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
//定义出大日期与小日期(假设)
Date max = *this;
Date min = d;
int flag = 1;
//先进行大小日期的判断,不符合则交换
if (*this < d)
{
max = d;
min = *this;
flag = -1;// 这里flag的作用:如果是小日期-大日期,应该是负数
}
int count = 0;
while (min != max)
{
//让小日期不断的累加,count记录天数
++min;
++count;
}
return count * flag;
}
//获取某天是周几
void Date::PrintWeekDay()const
{
const char* arr[] = { "周一","周二", "周三", "周四", "周五", "周六", "周日" };
/*Date start(1900, 1, 1);
int count = *this - start;*/
int count = *this - Date(1900, 1, 1);//匿名对象
cout << arr[count % 7] << endl;
}
⑥对流插入和流提取的重载
//Date.h
class Date
{
//友元函数
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
//构造函数
Date(int year = 1, int month = 1, int day = 1);
/*
......
......
*/
//void operator<<(ostream& out);//这里就不能实现成 成员函数
private:
int _year;
int _month;
int _day;
};
//实现为全局的
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
//Date.c
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;
}
六、const修饰类的成员函数
class Date
{
public:
void Display()
{
cout << "Display ()" << endl;
cout << "year:" << _year << endl;
cout << "month:" << _month << endl;
cout << "day:" << _day << endl << endl;
}
void Display() const
{
cout << "Display () const" << endl;
cout << "year:" << _year << endl;
cout << "month:" << _month << endl;
cout << "day:" << _day << endl << endl;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
void Test()
{
Date d1;
d1.Display();
const Date d2;
d2.Display();
}
七、取地址及const取地址操作符重载
class Date
{
public :
Date* operator&()
{
return this;
//return nullptr;不允许获取对象的地址
}
const Date* operator&()const
{
return this;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};