构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员 都有 一个合适的初始值,并且在对象的生命周期内只调用一次。
构造函数是特殊的成员函数,需要注意的是,构造函数的虽然名称叫构造,但是需要注意的是构造函数的主 要任务并不是开空间创建对象,而是初始化对象。
其特征如下:
1. 函数名与类名相同。
2. 无返回值。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载。
class Date
{friend ostream& operator<<(ostream& out, Date& d);
public:// 1.无参构造函数Date(){}// 2.带参构造函数Date(int year, int month, int day){this->_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};
ostream& operator<<(ostream& out, Date& d) {out << d._year << d._month << d._day << endl;return out;
}
void main()
{Date d1; // 调用无参构造函数Date d2(2015, 1, 1); // 调用带参的构造函数cout << d1;cout << d2;// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象//Date d3();
}
打印时没有调用Print()函数,而是用了运算符重载。使得打印更加方便。
传&是为了减少对拷贝构造的调用。
调无参构造后d1为随机值。
如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定 义编译器将不再生成。
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参 构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数。
析构函数
析构函数:
与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而 对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
特性
析构函数是特殊的成员函数。
其特征如下:
1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值。
3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
例子:
vector:
template <class T>
class vector
{
public:vector(): _a(nullptr), _size(0), _capacity(0){}~vector(){delete[]_a;_a = nullptr;_size = _capacity = 0;}void push_back(const T& x);/*{}*/void pop_back();size_t size(){return _size;} T& operator[](size_t i){assert(i < _size);return _a[i];}
private:T* _a;size_t _size;size_t _capacity;
};
拷贝构造函数
概念
在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。
构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象 创建新对象时由编译器自动调用。
拷贝构造函数也是特殊的成员函数,其特征如下:
1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
以日期类为例实现拷贝构造函数。
//拷贝构造
Date(const Date& d)
{this->_year = d._year;_month = d._month;_day = d._day;
}
日期的拷贝属于浅拷贝,编译器会生成。
若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷 贝,这种拷贝我们叫做浅拷贝,或者值拷贝。
但深拷贝的拷贝构造,需要自己构思。
传值的本质是拷贝构造,而拷贝构造又需要传参,故上图会陷入循环。
避免拷贝构造最好的方式就是使用&(引用)。
赋值运算符重载
运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类 型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型或者枚举类型的操作数
用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义
作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的
操作符有一个默认的形参this,限定为第一个形参
.* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。
以日期类为例:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Date
{friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator >> (istream& in, Date& d);
public://d2(d1) d2.Date(d1)int GetMouthDay(int year, int mouth) {static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int day = days[mouth];if (mouth == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {day += 1;}return day;}Date(){}Date(int year, int mouth, int day){this->_year = year;this->_mouth = mouth;this->_day = day;}void Print() {cout << _year << this->_mouth << this->_day;}//d1>d2--->!(d1<=d2)bool operator>(const Date& d){return !(*this <= d);}bool operator>=(const Date& d){return !(*this < d);}bool operator==(const Date& d) {if (this->_year == d._day && this->_mouth == d._mouth && this->_day == d._day){return true;}return false;}bool operator!=(const Date& d){return !(*this == d);}//d1<d2//d1.operator<(&d1,d2)inline bool operator<(const Date& d){if (this->_year < d._year){return true;}else if (this->_year == d._year && _mouth < d._mouth){return true;}else if(_year==d._year&&_mouth==d._mouth&&_day<d._day){return true;}return false;}bool operator <= (const Date & d){return *this < d || *this == d;}//d1+=10Date& operator += (int day){this->_day += day;while (_day > GetMouthDay(this->_year, this->_mouth)){_day -= GetMouthDay(this->_year, this->_mouth);_mouth++;if (_mouth == 13){++_year;_mouth = 1;}}return *this;}Date operator+(int day){Date ret(*this);ret += day;//ret.operator+=(day);return ret;}//d1+=10----d1.operator(&d1,10)Date& operator-=(int day) {this->_day -= day;while (this->_day <=0){this->_mouth--;if (_mouth == 0){--_year;_mouth = 12;}this->_day += GetMouthDay(_year, _mouth); }return *this;}Date operator-(int day){Date ret = *this;ret._day -= day;while (ret._day<=0){ret._mouth--;if (ret._mouth == 0){--ret._year;ret._mouth = 12;}ret._day += GetMouthDay(ret._year, ret._mouth);}return ret;}//++d1--->d1.operator++(&d1)Date& operator++(){*this += 1;return *this;//返回加之后的值}//d1++--->d1.operator++(&d1,0)Date operator++(int){Date tmp(*this);*this += 1;return tmp;}//d1-d2 利用n返回d1和d2所相差的天数int operator-(const Date& d) {int flag = 1;Date max = *this;//拷贝构造---浅拷贝---编译器可以自动生成Date min = d;if (*this < d){max = d;min = *this;flag = -1;}int n = 0;while (min != max&&min<max) {++min;++n;}return n+1;}void Scanf() {scanf("%04d%02d%02d", &this->_year, &this->_mouth, &this->_day);}cour->ostreamcin->istreamprivate:int _year;int _mouth;int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{out << d._year <<d._mouth << d._day << endl;return out;
}
istream& operator >> (istream& in, Date& d){in >> d._year >> d._mouth >> d._day;return in;}int main() {/*Date d1(0, 1, 1);Date d2(0, 1, 1);*//*Date d1(2022,2,10);Date d2(2022, 2, 1);*///cin >> d1 >> d2;/*while (cin>>d1>>d2){cout << d1 << d2;}*/Date d1, d2;//&& d2.Scanf()/*while (cin>>d1>>d2) {cout << d1 - d2;}*/d1.Scanf();d2.Scanf();/* cout << d1<<endl;cout << d2<<endl;*/cout << d1 - d2;
}
// 64 位输出请用 printf("%lld")