26 CPP运算符重载

 

 

#include <iostream>

using namespace std;

//非成员函数重载+ -
class Person {
public:
    Person() {
        m_score = 0;
        m_name.clear();
    }

    void show() {
        cout << m_name << " " << m_score << endl;
    }

    int m_score;
    string m_name;
};

//全局重载+号
void operator+(Person &p, int score) {
    p.m_score += score;
}

//全局重载-号
Person &operator-(Person &p, int score) {
    p.m_score -= score;
    return p;
}

void test() {
    Person p;
    p.m_score = 1;
    p + 10;
    p.show();
    p = p - 1 - 2;//同下
//    p = operator-(operator-(p, 1), 2);
    p.show();
}

int main() {
    test();
    return 0;
}
 11
 8
#include <iostream>

using namespace std;

//非成员函数重载+ -
class Person {
public:
    Person() {
        m_score = 0;
        m_name.clear();
    }

    void show() {
        cout << m_name << " " << m_score << endl;
    }

    void operator+(int score) {
        this->m_score += score;
    }

    Person &operator-(int score) {
        this->m_score -= score;
        return *this;
    }

    int m_score;
    string m_name;
};


void test() {
    Person p;
    p.m_score = 1;
    p + 10;
    p.show();
    p = p - 1 - 2;//同下
//    p = operator-(operator-(p, 1), 2);
    p.show();
}

int main() {
    test();
    return 0;
}

注意事项:

1 返回自定义数据类型的引用可以让多个运算符表达式串联起来。(不要返回局部变量的引用)

2 重载函数参数列表中顺序决定了操作数的位置(后面有代码说明)

3 重载函数的参数列表中至少有一个是用户自定义的类型,防止程序员为内置数据类型重载运算符

4 如果运算符重载既可以是成员函数也可以是全局函数,应该优先考虑成员函数,这样更符合运算符重载的初衷。

5 重载函数不能违背运算符原来的含义和优先级。(语法上没有限制不能这么做,但是这么做很垃圾)

6 不能创建新的运算符

7 以下运算符不可以重载

 

 8 以下运算符只能通过成员函数进行重载

 

 重载函数参数列表中顺序决定了操作数的位置 代码说明

#include <iostream>

using namespace std;

//重载函数参数列表中顺序决定了操作数的位置
class Person {
public:
    Person() {
        m_score = 0;
        m_name.clear();
    }

    void show() {
        cout << m_name << " " << m_score << endl;
    }

    int m_score;
    string m_name;
};

Person &operator+(Person &p, int score) {
    p.m_score += score;
    return p;
}

Person &operator+(int score, Person &p) {
    p.m_score += score;
    return p;
}

Person &operator+(Person &p1, Person &p2) {
    p1.m_score += p2.m_score;
    return p1;
}


void test() {
    Person p;
    p.m_score = 1;
    p + 10;
    p.show();
    //如上,重载的时候 Person &p, int score 顺序是这样,那么下面代码将报错
    p + 10 + p;//Invalid operands to binary expression ('void' and 'Person'
    //所以需要再写两个重载,顺序是int score,Person &p和Person &p1, Person &p2
    p.show();
}

int main() {
    test();
    return 0;
}

 

上图 关系运算符和左移运算符重载比较简单,其它几个运算符重载都有一些不一样的地方,C++编译器需要特别的处理。

重载左移运算符

#include <iostream>

using namespace std;

//左移运算符 cout
class People {
    friend ostream &operator<<(ostream &cout, const People &p);

    int m_age;
    int m_score;
public:
    People() {
        m_age = 18;
        m_score = 0;
    }

    ostream &operator<<(ostream &cout) {
        cout << m_age << " " << m_score << endl;
        return cout;
    }
};

ostream &operator<<(ostream &cout, const People &p) {
    cout << p.m_age << " " << p.m_score << endl;
    return cout;
}

void test() {
    People p;
    cout << p << endl;
    p << cout << endl;//如果是成员函数的重载,位置就不对了。
}

int main() {
    test();
    return 0;
}

重载下标运算符

 

 

 

 

 

注意:

1 编译器提供的默认赋值函数,是浅拷贝

2 如果对象不存在堆区内存空间,默认赋值函数可以满足需求,否则需要深拷贝。

3 赋值运算和拷贝构造不同:拷贝构造是指原来的对象不存在,用已存在的对象进行构造;赋值运算是指已经存在了两个对象,把其中一个对象的成员变量的值赋给另外一个对象的成员变量。

#include <iostream>

using namespace std;

//重载赋值运算符
class People {

public:
    int m_age;
    int m_score;
    int *m_ptr;

    People() {
        m_age = 18;
        m_score = 0;
        m_ptr = nullptr;
    }

    ~People() {
        if (m_ptr == nullptr) {
            delete m_ptr;
        }
    }

    void show() {
        cout << m_age << " " << m_score << endl;
        if (m_ptr != nullptr) {
            cout << *m_ptr << endl;
        }
    }

    People &operator=(const People &p) {
        //如果是自己给自己赋值
        if (this == &p) {
            return *this;
        }
        if (p.m_ptr == nullptr) {//如果源对象的指针为空,则清空目标对象的内存和指针
            if (m_ptr != nullptr) {
                delete m_ptr;
                m_ptr = nullptr;
            }
        } else {//源对象指针不为空
            //如果目标对象的指针为空,先分配内存
            if (m_ptr == nullptr) {
                m_ptr = new int;
            }
            //然后把源对象内存中的数据复制到目标对象的内存中
            memcpy(m_ptr, p.m_ptr, sizeof(int));
        }
        m_score = p.m_score;
        m_age = p.m_age;
        cout << "调用了重载赋值函数\n" << endl;
        return *this;
    }
};

void test() {
    People p1, p2;
    p1.m_score = 10;
    p1.m_age = 10;
    p1.m_ptr = new int(2);
    p1.show();
    p2.show();
    p2 = p1;
    p2.show();
}

int main() {
    test();
    return 0;
}
10 10
2
18 0
调用了重载赋值函数

10 10
2

 重载new&delete运算符

 

 

 

 

 

new[]和detele[]与 new和detele基本一致,在实际开发中,类用数组表示的 情况不多见,需要自定义分配内存的情况基本上没有,所以这两

为一个类重在new和delete时,尽管不必显示第使用static,但实际上仍在创建static成员函数 说明:

也就是说,声明这两个成员函数的时候,不管有没有写static关键字,它们都是静态成员函数,所以在这两个函数中,不能访问类的非静态成员。

#include <iostream>

using namespace std;

//为整型动态分配内存
void *operator new(size_t size) {
    cout << "调用了重载的new:" << size << "字节" << endl;
    void *p = malloc(size);
    cout << "申请到的内存地址是:" << p << endl;
    return p;
}

void operator delete(void *ptr) {
    cout << "调用了重载的delete" << endl;
//    if (ptr == 0) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
    if (ptr == nullptr) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
        return;
    }
    free(ptr);
}

void test() {
    //对于我们来说,C++的new和delete缺省屏蔽了全部细节,如果我们重载了new和delete运算符,就可以
    //用自己的代码申请和释放内存了。
    int *p = new int(1);
    cout << "p=" << p << ",*p=" << *p << endl;
    cout << "p=" << (void *) p << ",*p=" << *p << endl;
    delete p;


}

int main() {
    test();
    return 0;
}
/*
调用了重载的new:4字节
申请到的内存地址是:0x7fb2fc405910
p=0x7fb2fc405910,*p=1
p=0x7fb2fc405910,*p=1
调用了重载的delete
*/
#include <iostream>

using namespace std;

//为类动态分配内存  全局
void *operator new(size_t size) {
    cout << "调用了全局重载的new:" << size << "字节" << endl;
    void *p = malloc(size);
    cout << "申请到的内存地址是:" << p << endl;
    return p;
}

void operator delete(void *ptr) {
    cout << "调用了全局重载的delete" << endl;
//    if (ptr == 0) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
    if (ptr == nullptr) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
        return;
    }
    free(ptr);
}

class Person {
public:
    int m_age;
    int m_score;

    Person(int age, int score) {
        m_age = age;
        m_score = score;
        cout << "调用了构造函数Person(int age, int score)" << endl;
    }

    ~Person() {
        cout << "调用了析构函数~Person()" << endl;
    }

    void *operator new(size_t size) {
        cout << "调用了类重载的new:" << size << "字节" << endl;
        void *p = malloc(size);
        cout << "申请到的内存地址是:" << p << endl;
        return p;
    }

    void operator delete(void *ptr) {
        cout << "调用了类重载的delete" << endl;
//    if (ptr == 0) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
        if (ptr == nullptr) {//这是模拟C++的封装,所以C++中delete空指针也是安全的
            return;
        }
        free(ptr);
    }
};

void test() {
    //对于我们来说,C++的new和delete缺省屏蔽了全部细节,如果我们重载了new和delete运算符,就可以
    //用自己的代码申请和释放内存了。
    int *p = new int(1);
    cout << "p=" << p << ",*p=" << *p << endl;
    cout << "p=" << (void *) p << ",*p=" << *p << endl;
    delete p;
    cout << endl;
    Person *p2 = new Person(1, 2);
    cout << "p2的地址是" << p2 << " " << p2->m_age << " " << p2->m_score << endl;
    delete p2;


}

int main() {
    test();
    return 0;
}
调用了全局重载的new:4字节
申请到的内存地址是:0x7ff198c05910
p=0x7ff198c05910,*p=1
p=0x7ff198c05910,*p=1
调用了全局重载的delete

调用了类重载的new:8字节
申请到的内存地址是:0x7ff198c05910
调用了构造函数Person(int age, int score)
p2的地址是0x7ff198c05910 1 2
调用了析构函数~Person()
调用了类重载的delete

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值