Skip to content

重载演示

加号运算符重载

cpp
#include <iostream>
using namespace std;

class Person {
public:
    Person() {}
    Person(int a, int b) : m_A(a), m_B(b) {}

#if 0
    // 第一种实现方式
    // 利用成员函数实现【本质:p1.operator+(p2)】
    Person operator+(Person& p) {
        Person temp;
        temp.m_A = this->m_A + p.m_A;
        temp.m_B = this->m_B + p.m_B;
        return temp;
    }
#endif

    int m_A;
    int m_B;
};

// 第二种实现方式
// 利用全局函数实现【本质:operator+(p1, p2)】
Person operator+(Person& p1, Person& p2) {
    Person temp;
    temp.m_A = p1.m_A + p2.m_A;
    temp.m_B = p1.m_B + p2.m_B;
    return temp;
}

int main(int argc, char *argv[]) {
    Person p1(10, 10);
    Person p2(5, 6);
    Person p3 = p1 + p2;

    cout << "p3.m_A = " << p3.m_A << "    p3.m_B = " << p3.m_B << endl;

    system("pause");
}

程序输出:

shell
p3.m_A = 15    p3.m_B = 16

重载左移运算符

重载左移运算符——运算符重载碰上友元函数

友元函数是一个全局函数,和我们上例写的全局函数类似,只是友元函数可以访问某个类私有数据。

案例: 重载左移操作符 << ,使得cout可以输出对象。

cpp
#include <iostream>
using namespace std;

class Person {
    friend ostream& operator<<(ostream& out, Person& p);

public:
    Person(int a, int b) : m_A(a), m_B(b) {}

private:
    int m_A;
    int m_B;
};

// 输出的时间cout要写在左边,成员函数实现不了,只能使用全局函数实现
ostream& operator<<(ostream& out, Person& p) {
    out << "m_A = " << p.m_A << "    m_B = " << p.m_B;
    return out;
}

int main(int argc, char *argv[]) {
    Person p1(15, 20);
    cout << p1 << endl;

    return 0;
}

程序输出:

shell
m_A = 15    m_B = 20

自增自减运算符重载

重载的++--运算符有点让人不知所措,因为我们总是希望能根据它们出现在所作用对象的前面还是后面来调用不同的函数。解决办法很简单,例如当编译器看到++a前置++的时间,它就调用operator++(),当编译器看到a++后置++的时间,它就会去调用operator++(int),此时形参int只是一个占位参数。

cpp
#include <iostream>
using namespace std;

class Person {
    friend ostream& operator<<(ostream& out, Person& p);

public:
    Person() { this->m_Num = 0; }
    
    // 重载前置自增,返回自增之后的结果
    Person& operator++() {
        this->m_Num++;
        return *this;
    }
    
    // 重载后置自增,返回自增之前的结果
    Person operator++(int) {
        Person temp = *this;
        this->m_Num++;
        return temp;
    }

private:
    int m_Num;
};

ostream& operator<<(ostream& out, Person& p) {
    out << p.m_Num;
    return out;
}

int main(int argc, char *argv[]) {
    Person p1;
    cout << p1 << endl;
    cout << ++p1 << endl;
    p1++;
    p1++;
    cout << p1 << endl;

    return 0;
}

程序输出:

shell
0
1
3

如果定义了++a,也要定义a++,递增操作符比较麻烦,因为他们都有前缀和后缀形式,而两种语义略有不同。重载operator++operator--时应该模仿他们对应的内置操作符。

对于++--而言,后置形式是先返回,然后对象++或者--,返回的是对象的原值。前置形式,对象先++--,返回当前对象,返回的是新对象。其标准形式为:

调用代码时候,要优先使用前缀形式,除非确实需要后缀形式返回的原值,前缀和后缀形式语义上是等价的,输入工作量也相当,只是效率经常会略高一些,由于前缀形式少创建了一个临时对象。

指针运算符重载

指针运算符重载也被称为智能指针,用来管理开辟到堆区的实例对象释放内存空间。

cpp
#include <iostream>
using namespace std;

class Person {
public:
    Person() {}
    Person(int age) {
        this->m_Age = age;
        cout << "调用了有参构造函数" << endl;
    }
    ~Person() {
        cout << "调用了析构函数" << endl;
    }
    void ShowAge() {
        cout << this->m_Age << endl;
    }

private:
    int m_Age;
};

class SmartPoint {
public:
    SmartPoint(Person* p) {
        this->m_Person = p;
    }

    Person* operator->() {
        return this->m_Person;
    }

    // 此处如果不返回引用而返回Person则会调用两次析构函数
    Person& operator*() {
        return *m_Person;
    }

    ~SmartPoint() {
        if (this->m_Person) {
            delete m_Person;
            m_Person = NULL;
        }
    }

private:
    Person* m_Person;
};

int main(int argc, char *argv[]) {
    SmartPoint sp = (new Person(18));

#if 0
    sp->ShowAge();
#else
    (*sp).ShowAge();
#endif

    return 0;
}

程序输出:

shell
调用了有参构造函数
18

赋值运算符重载

赋值符常常初学者的混淆。这是毫无疑问的,因为=在编程中是最基本的运算符,可以进行赋值操作,也能引起拷贝构造函数的调用。

编译器默认至少会给类添加4个函数

  • 默认构造函数
  • 析构函数
  • 拷贝构造函数(值拷贝)
  • operator=(值拷贝)
cpp
#include <iostream>
using namespace std;

class Person {
public:
    Person() {}
    Person(char* name, int age) {
        this->m_Age = age;
        this->m_Name = new char[strlen(name) + 1];
        strcpy(this->m_Name, name);
    }
    /*
    ~Person() {
        if (this->m_Name != NULL) {
            delete[] this->m_Name;
            this->m_Name = NULL;
        }
    }
*/

    char* m_Name;
    int m_Age;
};

int main(int argc, char *argv[]) {
    Person p1("张三", 18);
    Person p2;
    p2 = p1;

    cout << "姓名:" << p2.m_Name << "  年龄:" << p2.m_Age << endl;

    return 0;
}

上面代码中Person p1("张三", 18);这一句在C++ 11标准之下虽然会有警告信息但是可以执行成功,在C++ 14及之后的标准下无法执行

将构造函数的参数char *name更改为const char *name即可。

即使没有上面的那一个问题,这段代码中也有其他的问题存在:若执行析构函数程序必然运行错误。

这是因为编译器默认替我们实现了operator=(){}的赋值运算符重载,将p1的属性值完全以值的方式拷贝给了p2,由此引发了浅拷贝的问题,因此在析构函数释放内存的时间程序就会出错。

自己动手实现赋值运算符的重载(函数内部实现深拷贝)即可解决此问题

cpp
#include <iostream>
using namespace std;

class Person {
public:
    Person() {}
    Person(char *name, int age) {
        this->m_Age = age;
        this->m_Name = new char[strlen(name) + 1];
        strcpy(this->m_Name, name);
    }

    Person& operator=(const Person &p) {
        if (this->m_Name != NULL)
        {
            delete[] this->m_Name;
            this->m_Name = NULL;
        }
        this->m_Name = new char[strlen(p.m_Name) + 1];
        strcpy(this->m_Name, p.m_Name);
        this->m_Age = p.m_Age;
        return *this;
    }

    ~Person() {
        if (this->m_Name != NULL) {
            delete[] this->m_Name;
            this->m_Name = NULL;
        }
    }

    char *m_Name;
    int m_Age;
};

int main(int argc, char *argv[]) {
    Person p1("张三", 18);
    Person p2;
    p2 = p1;

    cout << "姓名:" << p2.m_Name << "  年龄:" << p2.m_Age << endl;

    return 0;
}

以上就实现了赋值运算符的重载,但是对于Person p3 = p2;这种操作,需要自己再实现一下拷贝构造函数。

中括号运算符重载

对于上一节友元的强化训练中,如果想使用中括号来索引和赋值就需要对中括号进行重载,具体实现代码如下

cpp
int &operator[](int index){
    return this->pAdress[index];
}

等于和不等于运算符重载

cpp
#include <iostream>
#include <string>
using namespace std;

class Complex {
public:
    Complex(const char* name, int id, int age) {
        this->pName = new char[strlen(name) + 1];
        strcpy(this->pName, name);
        this->mID = id;
        this->mAge = age;
    }
    //重载==号操作符
    bool operator==(const Complex& complex) {
        if (strcmp(this->pName, complex.pName) == 0 &&
            this->mID == complex.mID &&
            this->mAge == complex.mAge) {
            return true;
        }
        return false;
    }
    //重载!=操作符
    bool operator!=(const Complex& complex) {
        if (strcmp(this->pName, complex.pName) != 0 ||
            this->mID != complex.mID ||
            this->mAge != complex.mAge) {
            return true;
        }
        return false;
    }
    ~Complex() {
        if (this->pName != NULL) {
            delete[] this->pName;
        }
    }

private:
    char* pName;
    int mID;
    int mAge;
};
void test() {
    Complex complex1("aaa", 10, 20);
    Complex complex2("bbb", 10, 20);
    if (complex1 == complex2) { cout << "相等!" << endl; }
    if (complex1 != complex2) { cout << "不相等!" << endl; }
}


int main(int argc, char *argv[]) {
    test();

    return 0;
}

程序输出:

cpp
不相等!

函数调用符号重载

cpp
#include <iostream>
using namespace std;
#include <string>

class MyPrint {
public:
    void operator()(string text) {
        cout << text << endl;
    }
};


void MyPrint2(string str) {
    cout << str << endl;
}

void test01() {
    MyPrint myPrint;
    myPrint("hello world");// 仿函数  本质是一个对象   函数对象

    MyPrint2("hello world");//普通函数
}


class MyAdd {
public:
    int operator()(int a, int b) {
        return a + b;
    }
};

void test02() {
    MyAdd myAdd;
    cout << myAdd(1, 1) << endl;


    cout << MyAdd()(1, 1) << endl;// 匿名函数对象 特点:当前行执行完立即释放
}

int main(int argc, char *argv[]) {

    test01();
    test02();

    return 0;
}

程序输出:

shell
hello world
hello world
2
2

仿函数写法不固定,比较灵活。