C++基础----类和对象(二)
文章目录
类的6个默认成员函数
构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,
以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
特性
析构函数
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
特性
class Stack
{
public:
//构造函数
Stack(size_t capacity = 3)
{
_array = (DataType*)malloc(sizeof(DataType) * capacity);
if (NULL == _array)
{
perror("malloc申请空间失败!!!");
return;
}
_capacity = capacity;
_size = 0;
}
//析构函数
//由于栈开辟的空间是在堆上,需要手动释放,故需要自己定义析构函数
~Stack()
{
if (_array)
{
free(_array);
_array = NULL;
_capacity = 0;
_size = 0;
}
}
class Time
{
public:
~Time()
{
cout << "~Time()" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 基本类型(内置类型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定义类型
Time _t;
};
int main()
{
Date d;
return 0;
}
// 程序运行结束后输出:~Time()
// 内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对象,
// 所以在 d销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。
// 但是main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函数
// 而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time类的析构函数
// 即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁
拷贝构造函数
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰)
在用已存在的类类型对象创建新对象时由编译器自动调用。
特征
赋值运算符重载
运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数
也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
日期类的运算符重载
class Date
{
public:
//任何一个类,只需要写一个> == 或者< ==重载
//剩下的比较运算符重载复用即可
//==运算符重载
bool operator==(const Date& d2)
{
return _year == d2._year
&& _month == d2._month
&& _day == d2._day;
}
// >运算符重载
bool operator>(const Date& d)
{
if (_year > d._year
|| (_year == d._year && _month > d._month)
|| (_year == d._year && _month == d._month && _day > d._day)
)
return true;
else
return false;
}
// >=运算符重载
bool 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);
}
static int getm(int year, int month)
{
int arrm[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;
}
else
{
return arrm[month];
}
}
//date+100 运算符重载
Date operator+(int d)
{
Date ret(*this);
ret._day+=d;
while (ret._day > getm(ret._year,ret._month))
{
ret._day-=getm(ret._year, ret._month);
ret._month+=1;
if (ret._month = 13)
{
ret._month = 1;
ret._year+=1;
}
}
return ret;
}
//date+=100 运算符重载
//方法一:
Date operator+=(int d)
{
_day += d;
while (_day > getm(_year, _month))
{
_day -= getm(_year, _month);
_month += 1;
if (_month > 12)
{
_year += 1;
}
}
return *this;
}
//方法二:
//效率差,调用了两次拷贝构造函数
Date operator+=(int d)
{
*this = *this + d;
return *this;
}
//d1-d2
//运算符重载 日期减少日期 结果是天数
int operator-(Date d)
{
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year; //年
int _month; //月
int _day; //日
};
int main()
{
Date d1;
Date d2;
//d1.operator++(&d1)
++d1;
//d1.operator++(&d2,0)
//后面只要传的是整数就行,是由编译器决定的
d2++;
return 0;
}
前置++和后置++重载
//++d1
//d1++
//直接按特性重载,无法区分
//特殊处理,使用重载区分,
//后置++重载增加一个int参数跟前置构成函数重载进行区分
Date& operator++()//前置
{
*this += 1;
return *this;
}
Date operator++(int)//后置
{
Date tmp(*this);
*this += 1;
return tmp;
}
赋值运算符重载格式
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回this :要复合连续赋值的含义
//赋值运算符重载
//*this出了这个函数的作用域还在,故用传引用返回,提高效率
Date& operator=(const Date& d)
{
//if是为了防止 出现d1=d1的情况,提高效率
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
//应对连续赋值的情况
return *this;
}
取地址及const取地址操作符重载
const成员
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,
实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
取地址操作符重载
class Date
{
//两个函数构成重载
//他们是默认成员函数,我们不写编译器会自动生成
//默认生成的就够用了,一般不需要我们自己写
public :
Date* operator&()
{
return this;
}
const Date* operator&()const
{
return this;
}
//特殊情况:当不想让别人取到这个类型对象的地址时,需要自己写
Date* operator&()
{
return nullptr;
}
const Date* operator&()const
{
return nullptr;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};