操作符重载(一)

一,运算符重载的基础知识

1.什么是运算符重载

  所谓的重载,就是重新赋予新的含义。函数的重载是让一个已经存在的函数赋予一个新的含义,使之实现新的功能。因此,一个函数名就可以用来代表不同功能的函数。运算符的重载其实我们已经使用过了,例如常见的"+"加法操作就是C++默认重载的,我们可以用加法对整数,单精度,双精度的数据进行加法运算,也是一个运算符可以有不同的功能。C++还为我们提供了自己进行运算符重载的方式。

2.运算符重载的推演

  我们可以自然而然的使用“+”号对两个整数或者浮点数进行求和运算,但是如果是复数呢,我们就不能简单的用“+”号来进行操作,就必须要用函数来进行两个复数的操作,下面来进行运算符重载的推演。

3.运算符重载推演代码的实现

# include<iostream>
using namespace std;

/* 定义复数类 */
class Complex
{
private:
    int a;
    int b;
    friend Complex& operator+(Complex& c1, Complex& c2);
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return this->a;
    }
    int getB()
    {
        return this->b;
    }
    void print()
    {
        cout << a << " + " << b << "i" << endl;
    }
};
/* 两个复数相加的函数 */
void add(Complex& c1, Complex& c2)
{
    Complex tmp(c1.getA() + c2.getA(), c1.getB() + c2.getB());
    
    tmp.print();
}
/* 定义operator+函数 */
Complex& operator+(Complex& c1, Complex& c2)
{
    Complex tmp(c1.a + c2.a, c1.b + c2.b);
    
    return tmp;
}

int main()
{
    Complex c1(1, 2);
    Complex c2(3, 4);
    /* 普通全局函数的两个复数相加 */
    add(c1, c2);
    /* operator+友元函数的两个复数相加 */
    Complex c3 = operator+(c1, c2);
    c3.print();
    /* 这时,我们替换operator+函数名称为+号,此时就是操作符的重载 */
    Complex c4 = c1 + c2;
    c4.print();

    return 0;
}

4.运算符重载的推演总结

  • 所谓的操作符重载,其本质还是函数,只是函数的名称换成了我们常见的操作符而已
  • 由于我们的类常常将类的属性设为私有,所以此时的操作符重载函数是友元函数,就可以快捷访问私有属性。 

 二,操作符重载编程基础

 1.操作符重载的两种方法

  • 操作符重载的本质函数为成员函数或者友元函数。
  • 关键区别在于成员函数有this指针,友元函数没有this指针。
  • 不管是友元函数重载还是成员函数重载,运算符的使用方法相同。但传递参数的方式不同,实现代码不同,应用的场合也不同。

2.二元运算符的重载

  • 所谓的二元运算符是指操作符对两个对象进行操作。例如常见的加法就是二元操作符,对两个数进行相加。
  • 二元运算符本质函数为成员函数,则成员函数参数只有一个,为操作符右边的数据,操作符左边的数据就是this指针对象。
  • 二元运算符本质函数为友元函数,则操作符的左右两边数据都由友元函数的参数来进行传递接收。

3.二元运算符两种重载方式的实现

# include<iostream>

using namespace std;

/* 定义复数类 */
class Complex
{
private:
    int a;
    int b;
public:
    /* 友元函数方式实现操作符(+)重载 */
    friend Complex& operator+(Complex& c1, Complex c2);
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    /* 成员函数方式实现操作符(-)重载 */
    Complex& operator-(Complex& c)
    {
        Complex tmp(this->a - c.a, this->b - c.b);
        return tmp;
    }
    void print()
    {
        cout << a << " + " << b + "i" << endl;
    }
};
/* 友元函数实现操作符重载的函数实现 */
Complex& operator+(Complex& c1, Complex c2)
{
    Complex tmp(c1.a + c2.a, c1.b + c2.b);
    return tmp;
}

int main()
{
    /* 定义两个复数 */
    Complex c1(1, 2), c2(3, 4);
    /* 测试操作符+,用友元函数实现 */
    Complex c3 = c2 - c1;
    c3.print();
    /* 测试操作符-,用成员函数实现 */
    Complex c4 = c1 + c2;
    c4.print();

    return 0;
}

4.一元操作符的重载

  • 所谓的一元操作符就是操作只有一个要操作的数据,例如常见的自加加和自减减。
  • 一元操作符分为前置方式和后置方式,例如a++和++a。C++通过一个占位参数来区分前置运算和后置运算。
  • 前置方式我们按照正常思路书写即可,分为成员函数和友元函数两个方式实现。
  • 后置方式我们需要进行操作符重载函数的重载,我们需要用占位符来实现重载。

5.一元操作符重载的代码实现

# include<iostream>
using namespace std;

class Complex
{
private:
    int a;
    int b;
public:
    /* 友元函数实现前置++运算符的重载 */
    friend Complex& operator++(Complex& c);
    /* 友元函数实现后置++运算符的重载 */
    friend Complex& operator++(Complex& c, int);
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    /* 成员函数实现前置--运算符的重载 */
    Complex& operator--()
    {
        --this->a;
        --this->b;
        return *this;
    }
    /* 成员函数实现后置--运算符的重载 */
    Complex& operator--(int)
    {
        /* 返回临时的this对象后,再进行this属性的减一运算 */
        Complex tmp(this->a, this->b);
        --this->a;
        --this->b;
        return tmp;
    }
    void print()
    {
        cout << a << " + " << b << "i" << endl;
    }
};
/* 友元函数实现前置++运算符的重载 */
Complex& operator++(Complex& c)
{
    ++c.a;
    ++c.b;
    return c;
}
/* 友元函数实现后置++运算符的重载 */
Complex& operator++(Complex& c,int)
{
    Complex tmp(c.a, c.b);
    ++c.a;
    ++c.b;
    return tmp;
}

int main()
{
    /* 定义复数 */
    Complex c1(1, 2);
    /* 前置++ */
    ++c1;
    c1.print();
    /* 前置-- */
    --c1;
    c1.print();
    /* 后置++ */
    Complex c2 = c1++;
    c2.print();
    c1.print();
    /* 后置-- */
    Complex c3 = c1--;
    c3.print();
    c1.print();

    return 0;
}

6.运算符重载的实现步骤

  • 首先必须承认操作符重载本质是一个函数,根据重载哪个操作符,书写哪个函数名称,例如:operator+()
  • 第二需要确认函数的参数,也就是确认操作符是操作几个数据,如复数自减减,则是一个数据。然后再确定是用友元函数还是成员函数实现。
  • 第三需要确认函数的返回值,也就是确认操作符运算后的结果是什么数据类型。

7.友元函数的使用场景

  • 当要重载的操作符左边是无法修改的类(例如:ostream)则必须使用友元函数,而无法使用成员函数(因为成员函数的左侧只能是this,即类的本身)。
  • =,[],(),和->操作符只能通过成员函数进行重载。
  • 友元函数重载运算符通常用于操作符两侧类型不一致的情况。

8.友元函数实现<<和>>操作符的重载

# include<iostream>
using namespace std;

class Complex
{
private:
    int a;
    int b;
public:
    /* 友元函数实现<<和>>操作符的重载 */
    friend ostream& operator<<(ostream& out, Complex& c);
    friend istream& operator>>(istream& in,  Complex& c);
};
/* 友元函数实现<<和>>操作符的重载 */
ostream& operator<<(ostream& out, Complex& c)
{
    out << c.a << " + " << c.b << "i";
    /* 返回输出流对象,让其支持链式编程 */
    return out;
}
istream& operator>>(istream& in, Complex& c)
{
    in >> c.a >> c.b;
    return in;
}

int main()
{
    /* 请输入一个复数 */
    cout << "请输入一个复数(实部和虚部用空格分开):" << endl;
    /* 定义一个复数 */
    Complex c;
    /* 接收输入的复数 */
    cin >> c;
    /* 打印接收的复数 */
    cout << c << endl;

    return 0;
}

 三,常见操作符的重载

1.重载赋值运算符=

# define _CRT_SECURE_NO_WARNINGS
# include<iostream>

using namespace std;

class Name
{
private:
    char * name;
public:
    /* 无参构造函数 */
    Name()
    {
        this->name = NULL;
        cout << "无参构造函数执行..." << endl;
    }
    /* 有参构造函数 */
    Name(char * name)
    {
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
        cout << "有参构造函数执行..." << endl;
    }
    /* 拷贝构造函数 */
    Name(const Name& n)
    {
        this->name = new char[strlen(n.name) + 1];
        strcpy(this->name, n.name);
        cout << "拷贝构造函数执行..." << endl;
    }
    /* 析构函数 */
    ~Name()
    {
        if (this->name != NULL)
        {
            delete[] this->name;
            this->name = NULL;
        }
        cout << "析构函数执行..." << endl;
    }
public:
    /* 等号操作符重载 */
    Name& operator=(Name& n)
    {
        cout << "等号操作符重载执行..." << endl;
        if (this->name != NULL)
        {
            delete[] this->name;
            this->name = NULL;
        }
        this->name = new char[strlen(n.name) + 1];
        strcpy(this->name, n.name);
        return *this;
    }
};

int main()
{
    Name n1("王刚");
    /* 拷贝构造执行 */
    Name n2 = n1;
    /* 赋值运算符 */
    Name n3;
    n3 = n2;

    return 0;
}

2.重载数组下标运算符[]

# include<iostream>

using namespace std;

class Vector
{
private:
    int * ptr;
    int len;
public:
    Vector(int len)
    {
        ptr = new int[len];
        this->len = len;
    }
    ~Vector()
    {
        if (this->ptr != NULL)
        {
            delete[] this->ptr;
            this->ptr = NULL;
        }
    }
public:
    /* 重载下标运算符 */
    int& operator[](int& i)
    {
        return this->ptr[i];
    }
};

int main()
{
    Vector v(10);
    /* 赋值 */
    for (int i = 0; i < 10; i++)
    {
        v[i] = i;
    }
    /* 获取元素 */
    for (int i = 0; i < 10; i++)
    {
        cout << v[i] << " ";
    }

    return 0;
}

3.重载函数调用符()

# include<iostream>
using namespace std;

class String
{
private:
    char * ptr;
public:
    /* 有参构造函数 */
    String(char * ptr)
    {
        this->ptr = new char[strlen(ptr) + 1];
    }
    /* 析构函数 */
    ~String()
    {
        if (this->ptr != NULL)
        {
            delete[] this->ptr;
            this->ptr = NULL;
        }
    }
public:
    /* 重载函数调用符() */
    String& operator()(char * ptr)
    {
        if (this->ptr != NULL)
        {
            delete[] this->ptr;
            this->ptr = NULL;
        }
        this->ptr = new char[strlen(ptr) + 1];
        strcpy(this->ptr, ptr);
        return *this;
    }
    /* 重载左移运算符 */
    friend ostream& operator<<(ostream& out, String& s);
};
/* 重载左移运算符 */
ostream& operator<<(ostream& out, String& s)
{
    out << s.ptr;
    return out;
}

int main()
{
    /* 调用有参构造函数 */
    String str("王刚");
    /* 调用重载操作符(),将王刚修改为张文婧 */
    str("张文婧");
    /* 打印str */
    cout << str << endl;
}
posted @ 2017-01-11 23:05  MetalSteel  阅读(663)  评论(0编辑  收藏  举报