【C++】赋值运算符重载 const 友元

1.赋值运算符重载

1.1运算符重载

C++为了增强可读性,让自定义类也能加减乘除比大小等运算,引入了运算符重载,运算符重载是具有特殊函数名的函数,函数参数个数是固定的。

ps:函数重载是函数名相同,参数不同的函数,系统会自动识别类型去调用相应的函数

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)以下列日期类为例

class Date//一个时间类

{

public:
 Date(int year = 1900, int month = 1, int day = 1)
 {//全缺省的构造函数
 _year = year;
 _month = month;
 _day = day;
 }

bool operator==(Date d)//这个就是==重载
{
	return (_year == d._year && _moth == d._moth && _day == d._day);
}
// bool operator==(Date* this,Date d)
// {//原本模样,在成员函数第一个参数是自己的指针称为this指针。
    //后面下面会用到这个知识点
//     return (this->_year == d._year && 
//     this->_moth == d._moth && this->_day == d._day);
// }//因为this经常用所以C++直接省略了

private://私人的,不可随意访问
 int _year;//函数成员
 int _month;
 int _day;
};

注意:

1.不能通过连接其他符号来创建新的操作符:比如operator@

2.重载操作符必须有一个类类型或者枚举类型的操作数。

(因为内置类型 像int这种,编译器已经重载好了,所以只能重载我们自定义的类型,类和枚举类型都是自定义类型)

3.用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义

(如果改变了就违背了,可读性就会大大下降)

4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的

操作符有一个默认的形参this,限定为第一个形参

(如上代码,成员函数第一个参数是自己的指针称为this指针。)

5.* :: sizeof?:. 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

1.2赋值运算符重载

赋值运算符(其实就是=运算符重载)有4个小点要注意

1. 参数类型

2. 返回值

3. 检测是否自己给自己赋值(别忘记啦O—O)

4. 返回*this(this是指向自己的指针,所以返回*this就是返回自己)

class Date

{

public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
 _year = year;
 _month = month;
 _day = day;
 }

Date& operator=(Date& d)//Date& 这个是运用了引用可以加快效率
{//这就是赋值运算符重载
     _year = d.year;
     _month = d.month;
     _day = d.day;
    return *this;
}

private:
 int _year;
 int _month;
 int _day;
};

5.一个类里没有去实现赋值运算符(=运算符),编译器也会自己实现一个,按照一个一个字节拷贝。 

class Date

{

public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
 _year = year;
 _month = month;
 _day = day;
 }

private:
 int _year;
 int _month;
 int _day;
};
 

int main()
{
 Date d1;
 Date d2(2018,10, 1);
 
 // 这里d1调用的编译器生成operator=完成拷贝,d2和d1的值也是一样的。

 d1 = d2;

 
 return 0;
}

那我们为什么要去实现这个=运算符重载呢??因为解决不了部分问题,比如开辟空间指针等就要自己去实现=运算符重载。如下程序也是这样崩溃的。

class String

{

public:
 String(const char* str = "")
 {
 _str = (char*)malloc(strlen(str) + 1);//
 strcpy(_str, str);
 }
 
 ~String()
 {
 cout << "~String()" << endl;
 free(_str);
 }
private:
 char* _str;
};
 

int main()
{
 String s1("hello");
 String s2("world");
 
 s1 = s2;
}

2.const

概念:const名 常量限定符,让变量具有常属性,不能随意的改动

修饰一般常量如下

int const a = 1;
const int a = 1;//俩种都一样

修饰指针

char a = '1';
char b = '2';
const char *p1 = a;//const指针使其内容不能改变,如下
//*p1 = '0';这个是会报错的
char const *p2 = a;//同上(以*分割,const在*左边作用一样,在*右边作用一样)
char *const p3 = a;//不能改变对象,p3内容可变,但只能指向a,如下
//*p3 = '0';可行
//p3 = b;不可行,对象不能变,哥们我纯情男大。
const char * const p4 = a;//内容和对象都不能改变

const修饰类的成员函数

将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改

这时就能给最上面的日期类加上const了。

class Date

{

public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
 _year = year;
 _month = month;
 _day = day;
 }

bool operator==(const Date& d)const//因为不用改变值所以可以用const
{
	return (_year == d._year && _moth == d._moth && _day == d._day);
}
private:
 int _year;
 int _month;
 int _day;
};

bool operator==(const Date& d)const  第一个const是修饰传过来的参数,第二个const是修饰this指针的,不让成员变量修改,这样可以减少错误的发生。(bool是返回类型)

3.友元

友元分为:友元函数和友元类

在类中 一般成员变量不想让别人看见、修改。所以设置成非公有的,要通过类内的成员函数(一般为公有)访问。其他类和其他函数是不能直接访问类内成员变量,但友元可以让他们实现,非常的方便,但方便的同时,关联性更强了以后想要修改其中一个就变得很麻烦。所以不宜多用。

3.1友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。(和普通函数一样就是要在类内加一个声明,声明的前面加一个friend)

问题:现在我们尝试去重载operator<<,然后发现我们会发现很奇怪,一般的是这样重载。

ostream& operator<<(ostream& out)//cout是ostream这个类型
{
	out << _year << '-' << _moth << '-' << _day << endl;
	return out;
}

但是为什么cout<<d;会报错而d<<cout;却可以用呢?是因为<<的左边是第一个参数,<<右边是第二个参数,而在上面代码this指针(隐藏起来了)在第一个位置,out在第二个位置,这个位置位置反了。所以不能让this指针放第一个参数。那就不能是类的成员函数,但如果放在类外面定义,那就不能访问类内的成员变量了,这时就要利用我们的友元函数了。如图下代码。

class Date

{//如下就是友元函数的声明

friend ostream& operator<<(ostream& _cout, const Date& d);

friend istream& operator>>(istream& _cin, Date& d);

public:
 Date(int year, int month, int day)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 

private:
 int _year;
 int _month;
 int _day;

};
 

ostream& operator<<(ostream& _cout, const Date& d)
{
 _cout<<d._year<<"-"<<d._month<<"-"<<d._day;
 
 return _cout;
}
 

istream& operator>>(istream& _cin, Date& d)
{
 _cin>>d._year;
 _cin>>d._month;
 _cin>>d._day;
 
 return _cin;
}
 

int main()
{
 Date d;
 cin>>d;
 cout<<d<<endl;
 return 0;
}

注意的小点

1.友元函数可访问类的私有和保护成员,但不是类的成员函数

2.友元函数不能用const修饰(因为没有this指针,函数用const是修饰this的)

3.友元函数可以在类定义的任何地方声明,不受类访问限定符限制

4.一个函数可以是多个类的友元函数

5.友元函数的调用与普通函数的调用和原理相同

3.2友元类

友元类所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

1.友元关系是单向的,不具有交换性。 比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。(如下代码)

2.友元关系不能传递 如果B是A的友元,C是B的友元,则不能说明C时A的友元。

class Date; // 前置声明

class Time

{
 friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成
员变量

public:
 Time(int hour, int minute, int second)
 : _hour(hour)//用了初始化列表
 , _minute(minute)
 , _second(second)
 {}
 

private:
 int _hour;
 int _minute;
 int _second;
};
 

class Date

{

public:
 Date(int year = 1900, int month = 1, int day = 1)
 : _year(year)//用了初始化列表
 , _month(month)
 , _day(day)
 {}
 
 void SetTimeOfDate(int hour, int minute, int second)
 {
 // 直接访问时间类私有的成员变量

 _t._hour = hour;
 _t._minute = minute;
 _t.second = second;
 }
 

private:
 int _year;
int _month;
 int _day;
 Time _t;
};

  • 37
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值