C++(四)

运算符重载

概念:类比于函数重载,同一个函数名,内部实现有区别,运算符也可以重载。如:<<左移 cout<<输出
可以被重载的运算符
算术运算符:+、-、、/、%、++、–
位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、
=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]
不被重载的运算符:
成员运算符 .、指针运算符 *、三目运算符 ? :、sizeof、作用域 ::

c++的运算符重载。默认只支持基本的数据类型。但是对自定义类类型不能直接使用,这时就需要运算符重载

格式

Integer operator + (const Integer& i1,const Integer& i2)
Integer:返回值
operator +:函数名

运算符重载可以用友元运算符重载,成员函数运算符重载,还有针对特别的其它运算符重载。

友元运算符重载

友元

熟悉
类的封装,一般成员属性设为private,提高安全性,如果需要访问,需要public接口。但有时,需要频繁的访问成员属性。需要调用函数就需要传参,而参数传递,类型检查和安全性检查会影响程序运行的效率。
概念
友元是定义在类外部的普通函数。但需要在类中进行说明。声明时需要用friend关键字。
目的
友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。不过,类的访问权限确实在某些应用场合显得有些呆板,从而容忍了友元这一特别语法现象。
而我们现有的学习友元的目的是为了后面运算符的重载,其他时候不用,会破坏封装。
友元函数的使用
1.定义在类外,不是类内函数,也就没有this指针。需要对象的引用作为参数,来访问对象中的成员
2.不是类内函数,友元函数的说明可以写在类中的任意位置,不受类中的权限控制。
例子

#include <iostream>
using namespace std;
class Test{
private:
    int a;
public:
    Test(int a)
    {
        this->a=a;
    }
    void show(){
        cout<<a<<endl;
    }
    friend void method(Test & t); //声明
};
//在类外
void method(Test & t){
    cout<<t.a<<endl;
}
int main()
{
    Test t1(2);
    t1.show();
    method(t1);
}

注意事项
如果类B时类A的友元类,类B就可以访问类A的所有成员
1.友元关系单向性,不具有交换性
2.友元关系不能传递 A和B B和C 但是A和C不是友元关系
3.友元关系不能继承 父亲的朋友 不是儿子的朋友

友元函数运算符重载
+操作符重载
#include <iostream>
using namespace std;
class Integer{ //定义的整型类
private:
    int a;
public:
    Integer(int a):a(a){}
    friend Integer operator + (const Integer& i1,const Integer& i2);
    int show(){
        return a;
    }
};
Integer operator + (const Integer& i1,const Integer& i2)
{
    return i1.a+i2.a; //值是int类型  Integer(int a)构造函数隐式触发
}
int main(){
   int a=2,b=3;
   cout<<a+b<<endl;
   double c=1.2,d=1.3;
   cout<<c+d<<endl;
   Integer p1(10);
   Integer p2(20);
   Integer p3=p1+p2; //相当于operator+(p1,p2)的简写
   cout<<p3.show()<<endl;
}

说明:首先类外定内声明,类外定义,用到关键字:friend,接着operator 关键字这是C++和pascal扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算符的使用方法与其原来一致,另一方面扩展其功能只能通过函数的方式(c++中,“功能”都是由函数实现的)。紧接着const:为了不让定重载的函数改变其值

前置++和后置++
#include <iostream>
using namespace std;
class Integer{ //定义的整型类
private:
    int a;
public:
    Integer(int a):a(a){}
    int show(){
        return a;
    }
    friend Integer operator ++(Integer & t1);
    friend Integer operator ++(Integer & t1,int);
};
Integer operator ++(Integer & t1){  //前置++
   return ++t1.a;
}
Integer operator ++(Integer & t1,int){
    return t1.a++;
}
int main(){
    Integer i2(10);
    //i2++;
    cout<<(++i2).show()<<endl; //11
    cout<<(i2++).show()<<endl; //11
    cout<<i2.show()<<endl;     //12
}

说明:和上面雷同,不同的是区分后置和前置++需要用到一个哑元参数区分

成员函数运算符重载

成员函数隐含this指针,可以指向当前对象,所以成员函数重载的参数都比友元函数重载少一个

例子

#include <iostream>
using namespace std;
class Integer{ //定义的整型类
private:
    int a;
public:
    Integer(int a):a(a){}
    //friend Integer operator + (const Integer& i1,const Integer& i2);
    Integer operator + (const Integer& other);
    //  friend Integer operator ++(Integer & t1);
    Integer operator ++();    //前置   
    //  friend Integer operator ++(Integer & t1,int);
    Integer operator ++(int); //后置    
    int show(){
        return a;
    }
};
Integer Integer::operator +(const Integer& other){
    return this->a+other.a;
}
Integer Integer::operator ++(){  //前置++
   cout<<"前置++"<<endl;
   return ++this->a;
}
Integer Integer::operator ++(int){
     cout<<"后置++"<<endl;
    return this->a++;
}
int main(){
    Integer i1(20);
    Integer i2(30);
    Integer i3=i1+i2; // 相当于i1.operator(i2)的简化
    cout<<i3.show()<<endl;
    cout<<(++i3).show()<<endl;
    cout<<(i3++).show()<<endl;

其他运算符重载(特殊的,选定的)

赋值运算符重载(将对象强转为数据类型)

写一个类的时候,默认会有构造函数,拷贝函数,析构,赋值函数。赋值运算符重载函数属于类内,是成员函数,所以它的重载只能通过显示的成员函数重载,不支持友元运算符重载
默认的形式 T & operator =(const T &) //T是任意的类型

#include <iostream>
using namespace std;
class Integer{ //定义的整型类
private:
    int a;
public:
    Integer(int a):a(a){}
    int show(){
        return a;
    }
    Integer & operator =(const Integer & right);
};
Integer& Integer::operator =(const Integer & right){
    cout<<"赋值运算符重载"<<endl;
    this->a=right.a;
    return *this;
}
int main(){
    Integer i1(20);
    Integer i2(30);

    i1=i2; //默认是可以的。因为有默认的赋值运算符函数
    cout<<i1.show();
}

注意:属性有指针类型的时候,需要赋值运算符重载。避免指针地址的值传递,不同对象属性用同一片内存区域,破坏对象之间的独立性。

类型转换运算符重载

可以使自定义类型的对象转换成任意类型。此函数也只能使用成员函数重载

#include <iostream>
using namespace std;
class Teacher{
private:
    string subject;//科目
public:
    Teacher(string subject)
    {
        this->subject=subject;
    }
    string get_subject(){
        return subject;
    } 
    operator string()
    {
        return subject;
    }
};
int main(){
    Teacher t1("C#");
    cout<<t1.get_subject()<<endl;
    string str="C";
    Teacher t2=str;
    cout<<t2.get_subject()<<endl;
    string str2=t2;
    cout<<str2<<endl;
}

注意事项
●运算符重载限制在C++已有的运算符范围内,不允许创建新的运算符。
●运算符重载也是函数重载,运算符也是函数。
●重载之后的运算符不能改变优先级和结合性。
●重载之后的运算符不能改变操作数和语法结构。
●运算符重载不能改变该运算符用于基本数据类型的含义,但是可以把基本数据类型与自定义类型一起运算,或者都使用自定义类型。
●运算符重载是针对新类型数据的实际需要对原有运算符的功能进行扩充,因此重载之后的功能应该与原有的功能类似,避免没有目的地使用运算符重载。
●通常建议单目运算符(一个操作数)使用成员函数运算符重载,双目运算符使用友元函数运算符重载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值