C++核心编程(十八)运算符重载

不能重载的运算符只有5个:

1. (成员访问运算符)。
(2.* (成员指针访问运算符)(我认为叫成员函数指针访问运算符比较贴切)。
(3)∷(域运算符)。
(4sizeof(长度运算符)。
(5?: (条件运算符

下面这个例子关于".*"的使用场景

#include<iostream>
using namespace std;
class A
{
public:
    void func()
    {
        cout<<"test\".*\""<<endl;//反斜杠是一个转译字符,因为我打了""添加\是为了不让编译器报错
    };
};

typedef void (A::*func)();//重定义一种数据类型类型,这种类型的返回值为void,属性是属于A类的成员函数的类型,是一种指针类型,类型名为func,
func p=&A::func;//创建一个指针p,指针的类型为func型,值为A类中成员函数func的地址。

int main()
{
    A obj;
    (obj.*p)();//.*的作用调用是通过函数指针访问成员函数
}

(1)加法运算符重载:
1)可以通过全局函数重载
2)可以通过成员函数重载
3)重载的函数名字固定,返回值类型为类的类型,返回一个匿名对象
4)重载不要滥用
5)重载无法改变运算符内置的属性

下面是关于加法运算符重载的例子:

#include<iostream>
using namespace std;
//#define global//全局函数重载开关
//#define rember//成员函数重载开关
#define int_class//将对象和数字相加的开关
class operator_overloading
{
public:
    operator_overloading();
#ifdef rember
    operator_overloading operator+(operator_overloading &obj);
#endif
#ifdef int_class
    operator_overloading operator+(int number);
#endif
    operator_overloading(int a,int b);
    int m_a;
    int m_b;
};
operator_overloading::operator_overloading()
{
}

operator_overloading::operator_overloading(int a,int b):m_a(a),m_b(b)
{
}

#ifdef rember
operator_overloading operator_overloading::operator+(operator_overloading &obj)//通过成员函数重载
{
    operator_overloading tempobj;
    tempobj.m_a=this->m_a+obj.m_a;
    tempobj.m_b=this->m_b+obj.m_b;
    return tempobj;
}
#endif

#ifdef int_class
operator_overloading operator_overloading::operator+(int number)
{
    this->m_a=this->m_a+number;
    this->m_b=this->m_b+number;
    return *this;   
}
#endif

#ifdef global 
operator_overloading operator+(operator_overloading &obj1,operator_overloading &obj2)
{
     operator_overloading tempobj;
    tempobj.m_a=obj1.m_a+obj2.m_a;
    tempobj.m_b=obj1.m_b+obj2.m_b;
    return tempobj;
}
#endif

int main()
{
    operator_overloading p1(1,0);
    operator_overloading p2(0,1);
#ifndef int_class
    operator_overloading p3=p1+p2;
    //成员函数重载相当于p3=p1.operator+(p2);
    //全局函数重载相当于p3=operator+(p1,p2);
#endif

#ifdef int_class
    operator_overloading p3=p1+10;//在上面的例子不支持p3=10+p;这种操作,本质上就是p3=p1.perator+(10);
#endif
    cout<<"p3_m_a="<<p3.m_a<<endl;
    cout<<"p3_m_b="<<p3.m_b<<endl;
}

(2)左移运算符
1)cout的类型是ostream输出流
2)重载左移运算符<<的时候不要用成员函数,因为成员函数,默认对象在左侧。
2)使用全局函数重载
4)通过全局友元函数访问私有变量
5)通过返回引用实现链式编程

#include<iostream>
using namespace std;
class left_move_char
{
    friend ostream & operator<<(ostream &cout,left_move_char &obj);
public:
    left_move_char();
    left_move_char(int a, int b);
private:
    int m_a;
    int m_b;
};
left_move_char::left_move_char(int a,int b):m_a(a),m_b(b)
{
}
left_move_char::left_move_char()
{
}
ostream& operator<<(ostream &cout,left_move_char &obj)
{
    cout<<obj.m_a<<endl;
    cout<<obj.m_b<<endl;
    return cout;
}
int main()
{
    left_move_char obj(10,20);
    left_move_char obj1(30,40);
    cout<<obj<<obj1;
}

递增运算符的重载
1)前加加是先计算,计算完成了再赋值
2)后加加是先赋值,然后继续计算
3)递增运算符的重载用成员函数重载即可
4)前++参数为空,后++参数为int(只能是int不能是其他类型,写个占位参数即可)

#include<stdio.h>>
int main()
{
    int a=1;
    printf("%d %d %d %d",++a,a++,a++,++a);
}

打印结果是5 3 2 5
从右往左边对a进行计算,对于前++来说它不及等最后计算完了再传给输出流,而后++很急,它每次轮到它就直接先传个输出流,然后再计算。
例子:重载递增运算符

#include<iostream>
using namespace std;
class progressive_increase
{
public:
    progressive_increase();
    progressive_increase(int a);
    progressive_increase& operator++();//前++没有占位符
    progressive_increase& operator++(int);//后++有个占位符
    int m_a;
};
progressive_increase::progressive_increase()
{ 
}
progressive_increase::progressive_increase(int a):m_a(a)
{
}
progressive_increase& progressive_increase::operator++(int)
{
 static   progressive_increase  *tempobj =new progressive_increase;
        *tempobj=*this;
         m_a++;
      	 cout<<"this指针的地址"<<this<<endl;
         cout<<"tempobj.m_a="<<tempobj->m_a<<endl;
        return *tempobj;
}
 progressive_increase&  progressive_increase::operator++()
{
        ++m_a;
        return *this;
}
ostream &operator<<(ostream &cout,progressive_increase &obj)
{
        cout<<obj.m_a;
        return cout;
}
int main()
{
  progressive_increase obj(0);
    cout<<++(++(++obj))<<endl; 
    cout<<((obj++)++)++<<endl;
    //后++相当于先把数字先传了,然后再进行进行后续的++,所以这里的操作实际上是
    //第一步obj.m_a的值传递给cout输出,第二步obj.m_a加1但是同时返回是*tempobj的别名,同时这个别名是个匿名对象
    //由于使用了static所以不用每次进函数都new
    //进函数就相当于对tempobj->m_a的别名进行++操作,同时每次返回别名
    //无论是前++还是后++都只会在终端上打印一次因为只有一个<<,其次是前++满足链式操作,后++不满足。
    //原因在于它们本身的特性就是,前++是把当前的变量先计算出最后值,再传递给到(这里是输出流)
    //后++是把当前的值先传递到(这里是输出流),然后在对把变量最后的值计算出来
}

3)赋值运算符的重载
1)赋值运算符的重载是为了避免浅拷贝
2)构造函数只会在初始化对象的时候调用,且只会调用一次,拷贝构造函数也属于构造函数
3)为解决赋值运算符默认是浅拷贝的问题,所以运用了重载赋值运算符

#include<iostream>
using namespace std;
class  shallow_deep_copy_constructor
{
public: shallow_deep_copy_constructor();
        shallow_deep_copy_constructor(int age);
        shallow_deep_copy_constructor(const shallow_deep_copy_constructor &obj);//使用引用只会开辟一个指针的空间,并且相当于取别名
        int *m_age;
        ~shallow_deep_copy_constructor();
        shallow_deep_copy_constructor& operator=(shallow_deep_copy_constructor &obj);
};
shallow_deep_copy_constructor::shallow_deep_copy_constructor()
{
    cout<<"默认构造函数"<<endl;
}
shallow_deep_copy_constructor::shallow_deep_copy_constructor(int age)
{
    m_age=new int(age);
    cout<<"带参数构造函数"<<endl;
}
shallow_deep_copy_constructor::shallow_deep_copy_constructor(const shallow_deep_copy_constructor &obj)
{
    if(m_age!=NULL)
    {
        delete m_age;
    }
    m_age=new int(*obj.m_age);
    cout<<"拷贝构造"<<endl;
}
shallow_deep_copy_constructor::~shallow_deep_copy_constructor()
{
    if(m_age!=NULL)
    {
        delete m_age;
    }
    cout<<"析构"<<endl;
}
shallow_deep_copy_constructor& shallow_deep_copy_constructor:: operator=(shallow_deep_copy_constructor &obj)
{
    if(m_age!=NULL)
    {
        delete m_age;
    }
    m_age=new int(*obj.m_age);
    return *this;
}
//#define init_test//测试构深拷贝浅拷贝及其默认赋值符号的作用。的开关
#define assigment_operator//测试赋值运算符重载后效果的开关

#ifdef init_test
void init_constructor_test()
{
    shallow_deep_copy_constructor obj(10);
    shallow_deep_copy_constructor obj1(1);
    shallow_deep_copy_constructor obj2=obj1;//我们定义的深拷贝构造函数只有在对对象初始化的时候才会调用
    cout<<"*obj2.m_age="<<*obj2.m_age<<endl;
    cout<<"*obj1.m_age="<<*obj1.m_age<<endl;
    cout<<"obj2.m_age"<<obj2.m_age<<endl;
    cout<<"obj1.m_age"<<obj1.m_age<<endl;

    cout<<endl;

    obj=obj1;//这样相当于浅拷贝,看打印地址就可以知道
    cout<<" *obj.m_age="<<*obj.m_age<<endl;
    cout<<"*obj1.m_age="<<*obj1.m_age<<endl;
    cout<<" obj.m_age="<<obj.m_age<<endl;
    cout<<"obj1.m_age="<<obj1.m_age<<endl;
}
#endif
#ifdef assigment_operator
void test_assignment_operator()
{
        shallow_deep_copy_constructor obj(10);
        shallow_deep_copy_constructor obj1(1);
        obj=obj1;//这样相当于浅拷贝,看打印地址就可以知道
        cout<<" *obj.m_age="<<*obj.m_age<<endl;
        cout<<"*obj1.m_age="<<*obj1.m_age<<endl;
        cout<<" obj.m_age="<<obj.m_age<<endl;
        cout<<"obj1.m_age="<<obj1.m_age<<endl;
}
#endif
int main()
{
    #ifdef init_test
        init_constructor_test();
    #endif

    #ifdef assignment_operator  
        test_assignment_satement();
    #endif
}

(4)关系运算符的重载
1)可以使用全局函数重载,也可以使用成员函数重载
2)最好形参中加const修饰,可以防止误操作

#include<iostream>
using namespace std;
class operator_relational
{
public:
    operator_relational();
    operator_relational(int number);
    bool operator==(const operator_relational &obj);//使用成员函数重载本质是(*this).operator==(obj)
    int m_number;
}; 
bool operator_relational::operator==(const operator_relational &obj)
{
    if(m_number==obj.m_number)return true;
    else return false;
}

bool operator!=(const operator_relational &obj,const operator_relational &obj1)//使用全局函数重载本质是operator!=(obj,obj1);
{
    if(obj.m_number==obj1.m_number)return false;
    else return true;
}
operator_relational::operator_relational()
{}
operator_relational::operator_relational(int number):m_number(number)
{}
int main()
{
    operator_relational obj(10);
    operator_relational obj1(20);
    cout<<(obj==obj1)<<endl;
    cout<<(obj!=obj1)<<endl;
}

(5)括号运算符的重载
1)括号运算符只能通过成员函数重载,不能通过全局函数重载
2)匿名对象的格式:类名();
例子:

#include<iostream>
using namespace std;

class brackets
{
public:
    int& operator()(int a,int b);
};
int& brackets::operator()(int a,int b)
{
    static int *temp=new int(a+b);
      cout<<"*temp="<<*temp<<endl;
        return *temp;
}
void test()
{
    brackets obj;
    int test=obj((4,3),2);//打印结果为3,实际上等于obj.(3,2);
    cout<<"test="<<test<<endl;

    cout<<brackets()(1,2)<<endl;//匿名函数对象
}
int main()
{
    test();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值