操作符重载!

操作符重载为操作符提供不同的语义

#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};
int main()
{
    Complex c1 = {1,2};
    Complex c2 = {3,4};
    Complex c3 = c1 + c2;//编译出错

    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}

上个例子中,不能用“+”直接操作两个结构体,改动一下,提供一个函数。

//增加一个add函数
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};
Complex add(const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}
int main()
{
    Complex c1 = {1,2};
    Complex c2 = {3,4};
    Complex c3 = add(c1,c2);//编译出错
    cout<<"c3.a = "<<c3.a<<endl;
    cout<<"c3.b = "<<c3.b<<endl;

    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}

C++中操作符重载的本质

C++中通过operator关键字可以利用函数拓展操作符,operator的本质是通过函数重载实现操作符重载。

//把add替换为“operator+"
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};
Complex operator+ (const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}

int main()
{
    Complex c1 = {1,2};
    Complex c2 = {3,4};
    Complex c3 = operator+ (c1,c2);
    cout<<"c3.a = "<<c3.a<<endl;
    cout<<"c3.b = "<<c3.b<<endl;
    c3 = c1 + c2;
    cout<<"c3.a = "<<c3.a<<endl;
    cout<<"c3.b = "<<c3.b<<endl;
    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}

operator关键字拓展的操作符应用到类。

利用友元friend关键字可以例外的开放private声明的类成员的使用权限

//友元friend和全局函数 使操作符重载应用与类
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a=0,int b=0)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    friend Complex operator+ (const Complex& c1,const Complex& c2);
};
Complex operator+ (const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}

int main()
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;
    cout<<"c3.a = "<<c3.getA()<<endl;
    cout<<"c3.b = "<<c3.getB()<<endl;
    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}

以上是“+”操作符,接下来重载“<<”操作符

//左移操作符重载
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a=0,int b=0)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    friend Complex operator+ (const Complex& c1,const Complex& c2);
    friend ostream& operator<< (ostream& out,const Complex& c);
};
Complex operator+ (const Complex& c1,const Complex& c2)
{
    Complex ret;
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    return ret;
}
ostream& operator<< (ostream& out,const Complex& c)
{
    out<<c.a<<"+"<<c.b<<"i";
    return out;//返回ostream类型的out 是为了能连续输出
}
int main()
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;
    //cout<<c1; -> operator<<(cout,c1) 如果没有返回cout的话,不能接着输出endl
    cout<<c1<<endl;//->((operator<<(cout,c1)))<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}

小结:

1、操作符重载的本质是通过函数扩展操作符的语义    2、operator关键字是操作符重载的关键

3、friend关键字可以函数或类开发访问权限               4、操作符重载遵循函数重载的规则

通过operator关键字能够讲操作符定义为全局函数,操作符重载的本质就是函数重载,那么类的成员函数是否可以作为操作符重载的函数

#include <iostream>
#include <cstdlib>
using namespace std;

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a,int b)
    {
        this ->a = a;
        this ->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    Complex operator+ (const Complex& c2);
    friend ostream& operator<< (ostream& out,const Complex& c);
};
Complex Complex::operator+ (const Complex& c2)
{
    Complex ret(0,0);
    ret.a = this->a + c2.a;
    ret.b = this->b + c2.b;
    return ret;
}
ostream& operator<< (ostream& out,const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";//数学里的虚数表示法
    return out;//考虑c++标准库重载的左移操作符支持链式调用,所以要返回cout,如果不返回,则不能接着返回endl了;
}
int main(int argc,char *argv[])
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;//->c3 = c1.operator+(c2)

    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

输出结果一样。

用成员函数重载的操作符比全局操作符函数少一个参数,即左操作符,而且不需要friend。

问题来了,什么时候用全局的函数重载,什么时候有成员函数重载。

1,当无法修改左操作数的类时,使用全局函数进行重载  2,=,[],(),->操作符只能通过成员函数进行重载。

//Array.h
#ifndef ARRAY
#define ARRAY
class Array
{
private:
    int mLength;
    int* mSpace;
public:
    Array(int length);
    Array(const Array& obj);
    int length();
    ~Array();
    int& operator[] (int i);
    Array& operator= (const Array& obj);
    bool operator== (const Array& obj);
    bool operator!= (const Array& obj);
};
#endif // ARRAY
//Array.c
#include "array.h"

Array::Array(int length)
{
    if(length < 0)
    {
        length = 0;
    }
    mLength = length;
    mSpace = new int[mLength];
}
Array::Array(const Array &obj)
{
    mLength = obj.mLength;
    mSpace = new int[mLength];
    for(int i = 0;i<mLength;i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}
int Array::length()
{
    return mLength;
}
Array::~Array()
{
    mLength = -1;
    delete[] mSpace;
}
int& Array::operator[] (int i)//作为左值的调用语句返回的必须是引用
{
    return mSpace[i];
}
Array& Array::operator= (const Array& obj)//返回Array的引用是为了可以连续赋值
{                                //a3 = a2 = a1;->a3 = a2.operator=(a1);
    delete[] mSpace;//先释放自己的原有的堆空间 因为接下来要申请
    mLength = obj.mLength;
    mSpace = new int[mLength];
    for(int i = 0;i<mLength;i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
    return *this;
}
bool Array::operator== (const Array& obj)
{
    bool ret = true;
    if(mLength==obj.mLength)
    {
        for(int i=0;i<mLength;i++)
        {
            if(mSpace[i] != obj.mSpace[i])
            {
                return false;
                break;
            }
        }
    }
    else
    {
        ret = false;
    }
    return ret;
}
bool Array::operator!= (const Array& obj)
{
    return !(*this == obj);
}
//main.c
#include <iostream>
#include <cstdlib>
#include "array.h"
using namespace std;

int main(int argc,char *argv[])
{
    Array a1(10);
    Array a2(0);
    Array a3(1);
    for(int i = 0;i<a1.length();i++)
    {
        a1[i] = i+  1;
    }

   for(int i = 0;i < a1.length();i++)
    {
        cout<<"Element"<<i<<":"<<a1[i]<<endl;
    }

     a2 = a1;//-> a2.operator=(a1);
     //a3 = a2 = a1;//->a3 = a2.operator=(a1);
    for(int i=0;i<a2.length();i++)
    {
         cout<<"Element"<<i<<":"<<a2[i]<<endl;
    }
    if(a1 == a2)
    {
        cout<<"a1 == a2"<<endl;
    }
    if(a3!=a2)
    {
        cout<<"a3 != a2"<<endl;
    }
    cout << "Press the enter key to continue ...";
    cin.get();
    return 0;
}

为什么要用到赋值操作符重载?

C++编译器会为每个类提供默认的赋值操作符,但默认的赋值操作符只是简单的值复制,一旦有指针类的成员变量则就只复制指针,它们将指向同一片空间,而相应的空间就没用了,所以类中存在指针成员变量时就需要重载赋值操作符

++操作符的重载

++操作符只有一个操作数,且有前缀和后缀的区分。如何重载++操作符才能区分前置运算和后置运算呢?

#include <iostream>
#include <cstdlib>
using namespace std;

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a,int b)
    {
        this ->a = a;
        this ->b = b;
    }
    int getA()
    {
        return a;
    }
    int getB()
    {
        return b;
    }
    Complex operator+ (const Complex& c2);
    Complex operator ++(int);//占位参数
    Complex& operator ++();
    friend ostream& operator<< (ostream& out,const Complex& c);
};
Complex Complex::operator+ (const Complex& c2)
{
    Complex ret(0,0);
    ret.a = this->a + c2.a;
    ret.b = this->b + c2.b;
    return ret;
}
ostream& operator<< (ostream& out,const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";//数学里的虚数表示法
    return out;//考虑c++标准库重载的左移操作符支持链式调用,所以要返回cout,如果不返回,则不能接着返回endl了;
}
Complex Complex:: operator ++(int)
{
    Complex ret = *this;//先将当前对象做一个备份
    /*首先解释++后缀的原理
     int a=0;
     cout<<a++<<endl;则会打印0 且a=1。
     为了模拟这个过程则要先保存一个当前值的备份
    */
    a++;//然后当前对象进行+1操作
    b++;
    return ret;//将备份返回
}
Complex& Complex:: operator ++()//为什么要返回引用?
{
    ++a;
    ++b;
    return *this;
}
int main(int argc,char *argv[])
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1 + c2;//->c3 = c1.operator+(c2)

    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

为什么不用重载&&和||操作符?

首先在语法上是没有错误的,但最好不要去重载,&&和||的特性是短路。

//短路
int a1 = 0;
int a2 = 1;
if(a1&&(a1+a2))
{
    cout<<"Hello"<<endl;
}
//因为a1=0,则(a1+a2)根本不会执行。这个就是所谓的短路。
//如果重载了&&
class Test
{
    int a;
public:
    Test(int i)
    {
      this->a = i;
    }
    Test operator+ (const Test& obj)
   {
      Test ret = 0;
       ret.a = this->a+obj.a;
       return ret;
    }
    bool operator&& (const Test& obj)
    {
        return a&&obj.a;
    }
};
Test t1 = 0;
Test t2 =1;
if(t1.operator&&(t1.operator+(t2)))
{
    cout<<"Hello"<<endl;
}
//则会先执行+操作,违反了短路原则。

&&和||是c++中非常特殊的操作符。

&&和||内置实现了短路规则,操作符重载是靠函数重载来实现的,操作数作为函数参数传递,c++的函数参数都会被求值,无法实现短路规则。

时间: 2024-09-29 10:02:07

操作符重载!的相关文章

Kotlin操作符重载:把标准操作加入到任何类中(KAD 17)

作者:Antonio Leiva 时间:Mar 21, 2017 原文链接:https://antonioleiva.com/operator-overload-kotlin/ 就像其他每种语言一样,在Kotlin中,已经预定义了一些操作符执行一定的操作. 最典型的是加(+),减(-),乘(*),除(/),而且还有很多. 类似Java这样的一些语言,这些操作符被限制在一些特定的数量类型上,且没有方法让其他类型数据使用这些操作符. 还有在像Scala这样的其他语言中,由于函数名称可接受任何符号,我

c++ --&gt; 操作符重载

一.什么是操作符重载 操作符重载可以分为两部分:“操作符”和“重载”.说到重载想必都不陌生了吧,这是一种编译时多态,重载实际上可以分为函数重载和操作符重载.运算符重载和函数重载的不同之处在于操作符重载重载的一定是操作符.我们不妨先直观的看一下所谓的操作符重载: #include <iostream> using namespace std; int main() { int a = 2 , b = 3; float c = 2.1f , d = 1.2f; cout<<"

Python中的操作符重载

类可以重载python的操作符 操作符重载使我们的对象与内置的一样.__X__的名字的方法是特殊的挂钩(hook),python通过这 种特殊的命名来拦截操作符,以实现重载. python在计算操作符时会自动调用这样的方法,例如: 如果对象继承了__add__方法,当它出现在+表达式中时会调用这个方法.通过重载,用户定义的对 象就像内置的一样. 在类中重载操作符 1.操作符重载使得类能拦截标准的python操作. 2.类可以重载所有的python的表达式操作符. 3.类可以重载对象操作:prin

操作符重载

class Program { int count; public Program() { } public Program(int count) { this.count = count; } static void Main(string[] args) { Program p1 = new Program(16); Program p2 = new Program(16); /** 操作符调用 */ Console.WriteLine(p1 + p2); Console.WriteLine

第二十篇:类操作符重载的相关规定与具体实现示例

前言 有书这么说过,C++设计的最大目的在于允许程序员定义自己的类型,并使它们用起来跟内置类型一样容易和直观.就目前看来,要实现这一点,最核心的莫过于操作符的重载.科学的重载可以让类的使用最大程度地接近内置类型.本文将讨论类操作符重载涉及到的一些原则和具体做法. 实现类操作符重载的两种思路 1. 友元函数法: 将待重载操作符视作非成员函数( 它声明为操作数类型的友元函数 ) 应当采用这种机制重载的运算符有:IO操作符,算数操作符,关系操作符. 2. 成员函数法: 将待重载操作符视作特殊的成员函数

拷贝构造函数 和 赋值操作符重载

什么时候需要定义自己的拷贝构造函数: 当类中包含有,动态分配成员 或者 指针 的时候. 如果使用默认构造函数,则新构造出来的 新类 和 旧类 里面的指针成员 指向同一个空间, 而当其中一个类 清空掉那个空间 .另一个类的指针就会变成野指针(因为空间已经被清空) , 也就是说默认构造函数是复制值(地址也是值) ps.基本数据类型的数组可以直接使用默认复制构造函数.也就是说有涉及到 自行开辟额外空间 的数据类型 和 指针 的类就需要 什么时候调用拷贝构造函数: 1.一个对象以 值传递 的方式 传入

操作符重载方法

CLR规范要求重载操作符重载方法必须是public和static方法 C#要求操作符重载方法至少有一个参数的类型与当前定义的这个方法类型相同 为了减少运行时开销,编译器会直接针对基元类型执行运算,并直接生成操作这些类型的实例的中间代码(IL)指令,所以在Framework标准库中没有定义基元类型的操作符重载 代码示例 public sealed class Complexe { public static Complexe operator +(Complexe c1, Complexe c2)

再议Swift操作符重载

今天我们来谈一谈Swift中的操作 符重载,这一功能非常实用,但是也相当有风险.正所谓“能力越大责任越大”,这句话用来形容操作符重载最合适不过了.它可以令你的代码更加简洁,也可以让 一个函数调用变得又臭又长.而对于那些没怎么读过你的代码的人来说,操作符的使用同时也会让代码的可读性大打折扣. 谨 慎引入,按需使用.比如在连接两个字串的时候你就可以通过重载加法来实现.甚至于你仅在屏幕上输入一个加号,就能响应一个网络链接.播放一段音乐或者完成 你能实现的其他任何功能.然而过于复杂的功能对编码来说简直就

操作符重载.xml

pre{ line-height:1; color:#1e1e1e; background-color:#d2d2d2; font-size:16px;}.sysFunc{color:#627cf6;font-style:italic;font-weight:bold;} .selfFuc{color:#800080;} .bool{color:#d2576f;} .condition{color:#000080;font-weight:bold;} .key{color:#000080;} .

【C/C++】操作符重载

常见问题 Q1. 下列运算符,在C++语言中不能重载的是( ). A. * B. ?: C. :: D. delete Q2. 编写类String的构造函数.析构函数和赋值函数. Q3. 复制构造函数与赋值运算符的区别是什么? Q4. 下述代码的输出结果是什么? 1 #include <iostream> 2 using namespace std; 3 class X 4 { 5 public: 6 X() { cout << "constructor" &l