运算符重载
类实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,仅能通过类的成员函数才能读写。如果数据成员定义为公共的,则又破坏了封装性。但是某些情况下,需要频繁读写类的数据成员,特别是在对某些成员函数多次调用时,由于参数传递、类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。
友元可以用在运算符重载
1.友元函数
友元函数在类外部的普通函数,需要类中用friend关键字进行说明。友元函数可以访问类中的私有成员
特点:
- 因为不是类内函数,没有this指针。参数需要是对象的引用,用于访问类中成员
- 友元函数不受类内权限修饰符的限制,友元函数的声明可以放在任意位置
#include
using namespace std;
class Person{
private:
//手机号 微信号 地址
string phoneNumber;
string weChat;
string address;
public:
Person(string p,string w,string a){
phoneNumber=p;
weChat=w;
address=a;
}
friend void friendMethod(Person& p);
};
void friendMethod(Person& p){
cout<<p.phoneNumber<<" "<<p.weChat<<" "<<p.address<<endl;
}
int main()
{
Person p1("180xxx1100","180xxx1100","银荷大厦");
friendMethod(p1);
}
2.友元类
当一个类是另一个类的友元类时,它就可以访问另一个类中所有的成员。需要friend关键字在另一个类中做说明
#include
using namespace std;
class A{
private:
int valueA;
public:
A(int n):valueA(n){}
friend class B; //B是A的友元类
};
class B{
public:
void show(A& a){
cout<<a.valueA<<endl;
}
};
int main()
{
A one(10);
B b;
b.show(one); //成员函数必须得用对象来调用
}
友元关系:单向性 不具有传递性 不能继承
3.运算符重载
在C++中,运算符的操作对象只能是基本数据类型。自定义类型是不能直接使用,所有运算重载对已有的运算符赋予多重含义。使同一个运算符作用与不同类型数据做出不同的行为
运算符重载的本质是函数重载,它也是C++多态的一种体现
运算符重载增强了C++的可扩充性,使得C++代码更加直观、易读
C++提供的运算符重载机制,重载运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要重载的运算符共同组成。和其他函数一样,重载运算符的函数也包括返回类型、参数列表及函数体,
可以被重载的运算符:
算术运算符:+、-、*、/、%、++、--
位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]
不被重载的运算符:
成员运算符 .、指针运算符 *、三目运算符 ? :、sizeof、作用域 ::
+运算符友元函数重载
#include
using namespace std;
class Rice{
private:
int production; //产量
int defense; //抗虫病,抗倒伏
public:
Rice(int production,int defense){
this->production=production;
this->defense=defense;
}
friend Rice operator + (Rice& one,Rice& two);
void show(){
cout<<"产量:"<<production<<" 抗性:"<<defense<<endl;
}
};
Rice operator + (Rice& one,Rice& two){ //友元函数的运算符重载
int pro=(one.production+two.production)/2;
int def=(one.defense+two.defense)/2;
Rice r(pro,def);
return r;
}
int main()
{
//自定义的类 实现加的操作
Rice r1(1000,30);
Rice r2(500,90);
Rice r3=r1+r2; //相当于Rice r3=operator+(r1,r2);
r3.show();
}
++操作符
基本数据类型
#include
using namespace std;
int main()
{
int n=10;
cout<<++n<<endl; //11
cout<<n++<<endl; //11
cout<<n<<endl; //12
}
++操作符友元函数重载
用int做参数占位,代表后置++
#include
using namespace std;
class Integer{ //整数类
private:
int value;
public:
Integer(int value):value(value){}
void show(){
cout<<value<<endl;
}
friend Integer operator ++(Integer& other); //前置++
friend Integer operator ++(Integer& other,int); //后置++
};
Integer operator ++(Integer& other){
//值先变化 再返回
cout<<"前置++"<<endl;
other.value++;
return other;
}
Integer operator ++(Integer& other,int){
//返回的是旧值
Integer t(other); //拷贝构造保存对象旧的值
other.value++;
return t;
}
int main()
{
Integer i(10);
i.show();//10
(++i).show();//11 //相当于operator ++(i).show();
(i++).show();//11
i.show(); //12
}
成员函数都有一个隐含this指针。可以比友元函数重载少一个参数,隐含的this指针作为成员函数的第一个参数存在
+运算符的成员函数重载
#include
using namespace std;
class Rice{
private:
int production; //产量
int defense; //抗虫病,抗倒伏
public:
Rice(int production,int defense){
this->production=production;
this->defense=defense;
}
//friend Rice operator + (Rice& one,Rice& two);
Rice operator + (Rice& two);
void show(){
cout<<"产量:"<<production<<" 抗性:"<<defense<<endl;
}
};
//成员函数重载
Rice Rice::operator + (Rice& two){
cout<<"地址值"<<this<<endl;
int pro=(this->production+two.production)/2;
int def=(this->defense+two.defense)/2;
Rice r(pro,def);
return r;
}
int main()
{
//自定义的类 实现加的操作
Rice r1(1000,30);
Rice r2(500,90);
cout<<&r1<<endl;
Rice r3=r1+r2; //相当于 Rice r3=r1.operator+ (r2);
r3.show();
}
++操作符的成员函数重载
#include
using namespace std;
class Integer{ //整数类
private:
int value;
public:
Integer(int value):value(value){}
void show(){
cout<<value<<endl;
}
//friend Integer operator ++(Integer& other); //前置++
Integer operator ++();
//friend Integer operator ++(Integer& other,int); //后置++
Integer operator ++(int);
};
Integer Integer::operator ++(){ //类外实现
//值先变化 再返回
cout<<"前置++"<<endl;
this->value++;
return *this;
}
Integer Integer::operator ++(int){
//返回的是旧值
Integer t(*this);
this->value++;
return t;
}
int main()
{
Integer i(10);
i.show();//10
(++i).show();//11
(i++).show();//11
i.show(); //12
}
创建一个类编译器会提供默认的构造,析构和拷贝构造,除此之后,还有赋值运算符重载
赋值运算符重载
作用:用一个对象的值改变另一个对象的值
形式: T& operator =(const T& other) ;// T可以是任意类型
特点:是类内函数,只支持成员函数重载
不显示给出赋值运算符函数时,编译器会给出默认的赋值运算符函数,完成对象间的赋值。
但是当属性有指针类型的时候,这时需要显示写出赋值运算符函数,类似于浅拷贝出现的问题
#include
using namespace std;
class Integer{ //整数类
private:
int value;
public:
Integer(int value):value(value){}
void show(){
cout<<value<<endl;
}
Integer& operator =(const Integer& other){
cout<<"赋值运算符函数调用"<<endl;
this->value=other.value;
}
};
int main()
{
int a=10,b=20;
a=b; //b的值给a
Integer one(10);
Integer two(20);
one=two; //赋值 //
one.show(); //20
}
类型转换运算符函数
作用:把自定义类型转成任意类型
特点:1.只支持成员函数重载
2.不需要写返回值
#include
using namespace std;
class Student{
private:
string name;
int age;
public:
Student(string name){
this->name=name;
}
Student(string name,int age){
this->name=name;
this->age=age;
}
//类型转换
operator string(){
return name;
}
operator int(){
return age;
}
};
int main()
{
string str="小红";
Student s=str; //隐式调用构造函数
string str2=s;
cout<<str2<<endl; //小红
Student s2("小刚",20);
int n=s2;
cout<<n<<endl; //20
}
运算符重载注意事项:
●运算符重载限制在C++已有的运算符范围内,不允许创建新的运算符。
●运算符重载也是函数重载,运算符也是函数。
●重载之后的运算符不能改变优先级和结合性。
●重载之后的运算符不能改变操作数和语法结构。
●运算符重载不能改变该运算符用于基本数据类型的含义,但是可以把基本数据类型与自定义类型一起运算,或者都使用自定义类型。
●运算符重载是针对新类型数据的实际需要对原有运算符的功能进行扩充,因此重载之后的功能应该与原有的功能类似,避免没有目的地使用运算符重载。