各位大佬大家好,我是猪皮兄弟
今天的内容是运算符重载,内置类型可以直接使用运算符运算,因为编译器知道该如何进行运算,自定义类型无法直接使用运算符,编译器也不知道该如何运算,如果想要让编译器支持,就需要自己实现运算重载
C++为了增加代码的可读性增加了运算符重载,运算符重载是具有特殊函数名的函数,也具有返回类型,函数名字以及参数列表,其返回值和参数列表与普通函数相似,最大的不同就是它具有特殊的函数名
函数名为:关键字operator后跟需要重载的运算符
返回值和参数列表由操作符的性质决定
1.类中提供获取成员变量的函数,来返回成员变量
2.友元、但是友元破坏了封装,所以不建议使用
3.将函数写在类里
运算符重载的第一个参数也就是this指针是在运算符前面的,比如==的运算符重载
d1==d2; d1就是this指针的参数
对于大结构体来说,传引用是很提高效率的,并且里面不需要改变,最好加上const,保证安全(保证里面不会写错),另外,因为this指针我们不能显示写,所以C++中为了修饰this指针指向的内容不能改变,就只能加在后面,如下所示
class Date
{
public:
Date(int year=1,int month=1,int day=1)
{
_year=year;
_month=month;
_day = day;
}
bool operator==(const Date&d) const
{
return _year==d._year
&& _month==d._month
&& _day==d._day;
}
private:
int _year;
int _month;
int _day;
};
class Date
{
public:
Date(int year=1, int month=1, int day=1)
:_year(year)
, _month(month)
, _day(day)//初始化列表,后面讲
{
}
bool isLeapYear(int year)
{
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
size_t getMonthDay(size_t year, size_t month)
{
if (isLeapYear(year) && month == 2)
return 29;
return arr[month];
}
//当然这里不传引用也是可以
Date& operator+=(const size_t& day)
{
_day += day;
while (_day > getMonthDay(_year, _month))
{
_day -= getMonthDay(_year, _month);
_month++;
if (_month == 13)
_year++;
}
return *this;//因为支持连续+=;
}
private:
int _year;
int _month;
int _day;
static int arr[13];//定义一个静态的数组,方便获得每月的天数
};
int Date::arr[13] = { 0,31,28,31,30,31,20,31,31,30,31,30,31 };
class Date
{
public:
Date(int year=1, int month=1, int day=1)
:_year(year)
, _month(month)
, _day(day)//初始化列表,后面讲
{
}
bool isLeapYear(int year)
{
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
size_t getMonthDay(size_t year, size_t month)
{
if (isLeapYear(year) && month == 2)
return 29;
return arr[month];
}
//当然这里不传引用也是可以
Date operator+(const size_t& day) const
{
Date ret=*this;//拷贝构造
ret._day += day;
while (ret._day > getMonthDay(ret._year, ret._month))
{
ret._day -= getMonthDay(ret._year, ret._month);
ret._month++;
if (ret._month == 13)
ret._year++;
}
return ret;
}
private:
int _year;
int _month;
int _day;
static int arr[13];//定义一个静态的数组,方便获得每月的天数
};
int Date::arr[13] = { 0,31,28,31,30,31,20,31,31,30,31,30,31 };
赋值运算符重载只能重载与成员,不能重载于全局,因为赋值运算符重载是默认成员函数,不写也会自动生成,所以,重载于全局的话会起冲突!
注意,赋值也是可以连续赋值的
class Date
{
public:
Date(int year=1, int month=1, int day=1)
:_year(year)
, _month(month)
, _day(day)//初始化列表,后面讲
{
}
Date& operator=(const Date& d)//支持连续赋值
{
if(this!=&d)
{
_year=d._year;
_month=d._month;
_day=d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
赋值运算符重载也是默认成员函数,我们不显示写时编译器默认生成,以值拷贝(浅拷贝)的方式逐字节进行,同样,对于内置类型直接浅拷贝,对于自定义类型,调用对应的默认赋值运算符重载函数完成赋值,所以像日期类这种就不需要自己写了,但是如果是自己开辟空间的那种,就需要自己来实现深拷贝完成赋值。
原因:
1.浅拷贝拷贝出来的地址和参数是相同的,所以会存在可以互相修改的问题
2.会被free或者delete两次,报错
1.大部分的类都要自己去实现构造函数,除了像用两个栈来实现队列的这一种类,这个队列会去
调用栈的构造函数,所以不用自己写。
2.每个类最好都提供不传参数的构造函数
a.编译器生成的构造
b.自己写的无参构造
c.全缺省构造
3.对于析构,只需要自己申请了空间的类去写,包括两个栈实现队列的也不用写(栈要写,队列不写),而栈帧和栈的性质相似,所以先定义的后析构,后定义的先析构。
4.拷贝构造函数其实是构造函数的重载
对于重载,发现void func(int a)和void func(int&aa)构成重载,因为函数名的修饰规则不同
但是又发现typeid(a).name()和typeid(aa).name()都是int
5.拷贝构造和赋值运算符重载对于不需要深拷贝的类就不用写,默认使用的浅拷贝足够
6.很多运算符重载都是可以复用的,比如说+=和+,> >= < <=.
为了对前置++和后置++和前置–和后置–做区分,C++对于这一点利用函数重载去区分
Date& operator++();//前置
Date& operator++(int);//后置
首先说明
cin和cout是对象而不是函数
cin是istream的对象
cout是ostream的对象
流插入<<和流提取>>需要写成全局的,因为在类里,cin无法作为左操作数,而cin或者cout
cout<<1<<2<<3<<endl;
cin>>a>>b>>c;
//因为cin和cout需要当左操作数,所以写成全局的,不受this指针影响。
所以正确写法:
class Date()
{
friend ostream& operator<<(ostream&out,const Date& d);
public:
Date(int year=1,int month=1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{
}
private:
int _year;
int _month;
int _day;
};
//cout与cin类似
inline ostream& operator<<(ostream&out,const Date& d)
{
//因为在类外,获得private成员变量三种方式
1.类里写get的函数
2.友元,不建议使用,破坏封装,但是这里用一下友元
3.私有改公有
out<<d._year<<'.'<<d._month<<'.'<<d._day<<endl;
return out;
}
因为会频繁的调用,所以写成内敛,但是注意,这里不能够声明于定义分离,因为内敛不会进符号表。如果分离,那么在链接的时候找不到函数地址而出现链接错误
1.运算符重载不能够去创造新的运算符
2.重载操作必须有一个类类型参数
3.重载的含义不能改变,比如说+去实现*
4.有隐含的this指针
5.有几个操作符是不能够被重载的
a.域作用限定符 ::
b.sizeof()
c.三目运算符 ?:
d. .点
e. .*点乘
对于这个运算符来说,因为他是默认成员函数,编译器会自己生成,并且,编译器自己生成的也就够用了,所以一般不用我们自己写,除非遇到特殊的场景:比如我不想让别人拿到我的地址:
//const在*之前修饰指针指向的内容
//const在*之后修饰指针
A* operator&()//Date *const this默认参数
{
return nullptr;
}
上面对C++运算符重载重要知识点进行了总结,感谢大家的支持,后面我会继续更新类和对象有关方面的内容!