C++面向对象-运算符重载

运算符重载

运算符重载又称为操作符重载,可以为运算符增加一些新的功能,全局函数和成员函数都支持运算符重载,我们通过具体的实例来演示下,我们声明一个Point类,并且定义需要通过运算符重载的类。

#pragma once
#include 
using namespace std;

class Point {
    friend ostream &operator<<(ostream &, const Point &);
    int m_x;
    int m_y;
public:
    Point(int x, int y);
    // 两个对象+ 赋值新的对象
    Point operator+(const Point &point) const;
    // 两个对象- 赋值老的对象
    Point operator-(const Point &point) const;
    //取反
    const Point operator-() const;
    // +=
    Point &operator+=(const Point &point);
    // -=
    Point &operator-=(const Point &point);
    // 是否相等
    bool operator==(const Point &point);
    // 是否不等
    bool operator!=(const Point &point);
    // 前++
    Point &operator++();
    // 后++ 注意int为固定写法
    const Point operator++(int);
};

Point实现如下:

#include "Point.h"

Point::Point(int x, int y) :m_x(x), m_y(y) { }

// 运算符(操作符)重载
Point Point::operator+(const Point &point) const {
    return Point(this->m_x + point.m_x, this->m_y + point.m_y);
}

Point Point::operator-(const Point &point) const {
    return Point(this->m_x - point.m_x, this->m_y - point.m_y);
}

const Point Point::operator-() const {
    return Point(-this->m_x, -this->m_y);
}

Point &Point::operator+=(const Point &point) {
    this->m_x += point.m_x;
    this->m_y += point.m_y;
    return *this;
}

Point &Point::operator-=(const Point &point) {
    this->m_x -= point.m_x;
    this->m_y -= point.m_y;
    return *this;
}

bool Point::operator==(const Point &point) {
    return (this->m_x == point.m_x) && (this->m_y == point.m_y);
}

bool Point::operator!=(const Point &point) {
    return (this->m_x != point.m_x) || (this->m_y != point.m_y);
}

// 前++
Point &Point::operator++() {
    this->m_x++;
    this->m_y++;
    return *this;
}

// 后++
const Point Point::operator++(int) {
    Point point(this->m_x, this->m_y);
    this->m_x++;
    this->m_y++;
    return point;
}

ostream &operator<<(ostream &cout, const Point &point) {
    return cout << "(" << point.m_x << ", " << point.m_y << ")";
}

main.cpp调用如下:

    Point p0(5, 10);
    Point p1(30, 70);
    Point p2(10, 40);
    Point p3 = p1++ - p0;
    (p1 += p2) = Point(100,300);
    Point p4 = ++p1 - p0;
    
    //以下两个调用等价
    p1 += p2;
    p1.operator+=(p2);
    
    //以下两个调用等价
    cout << p1;
    operator<<(cout,p1);
    

注意,运算符重载最好跟系统的用法靠近,比如前++和后++的重载,以及考虑到const对象等。重载cout函数不能放到成员函数实现,因为cout在对象前,最好声明成类的友元函数,便于访问成员变量的值。下面我们自己再维护一个String类,实现C++标准库string的一些功能。

#pragma once
#include 
using namespace std;

class String {
    friend ostream &operator<<(ostream &, const String &);
public:
    String(const char *cstring = "");
    String(const String &string);
    ~String();
    String &operator=(const char *cstring);
    String &operator=(const String &string);
    String operator+(const char *cstring);
    String operator+(const String &string);
    String &operator+=(const char *cstring);
    String &operator+=(const String &string);
    bool operator>(const char *cstring);
    bool operator>(const String &string);
    char operator[](int index);
private:
    char *m_cstring = NULL;
    String &assign(const char *cstring);
    char *join(const char *cstring1, const char *cstring2);
};



#include "String.h"

String::String(const char *cstring) {
    assign(cstring);
}

String::String(const String &string) {
    assign(string.m_cstring);
}

String::~String() {
    assign(NULL);
}

String &String::operator=(const char *cstring) {
    return assign(cstring);
}

String &String::operator=(const String &string) {
    return assign(string.m_cstring);
}

String String::operator+(const char *cstring) {
    String str;
    char *newCString = join(this->m_cstring, cstring);
    if (newCString) {
        // 释放旧的堆空间
        str.assign(NULL);
        // 直接指向新开辟的堆空间
        str.m_cstring = newCString;
    }
    return str;
}

String String::operator+(const String &string) {
    return operator+(string.m_cstring);
}

String &String::operator+=(const char *cstring) {
    char *newCString = join(this->m_cstring, cstring);
    if (newCString) {
        this->assign(NULL);
        this->m_cstring = newCString;
    }
    return *this;
}

String &String::operator+=(const String &string) {
    return operator+=(string.m_cstring);
}

bool String::operator>(const char *cstring) {
    if (!this->m_cstring || !cstring) return 0;
    return strcmp(this->m_cstring, cstring) > 0;
}

bool String::operator>(const String &string) {
    return operator>(string.m_cstring);
}

char String::operator[](int index) {
    if (!this->m_cstring || index < 0) return '\0';
    if (index >= strlen(this->m_cstring)) return '\0';
    return this->m_cstring[index];
}

char *String::join(const char *cstring1, const char *cstring2) {
    if (!cstring1 || !cstring2) return NULL;

    char *newCString = new char[strlen(cstring1) + strlen(cstring2) + 1] {};
    strcat(newCString, cstring1);
    strcat(newCString, cstring2);

    cout << "new[] - " << newCString << endl;
    return newCString;
}

String &String::assign(const char *cstring) {
    // 指向一样的堆空间
    if (this->m_cstring == cstring) return *this;

    // 释放旧的字符串
    if (this->m_cstring) {
        cout << "delete[] - " << this->m_cstring << endl;

        delete[] this->m_cstring;
        this->m_cstring = NULL;
    }

    // 指向新的字符串
    if (cstring) {
        cout << "new[] - " << cstring << endl;

        this->m_cstring = new char[strlen(cstring) + 1]{};
        strcpy(this->m_cstring, cstring);
    }

    return *this;
}

ostream &operator<<(ostream &cout, const String &string) {
    if (!string.m_cstring) return cout;
    return cout << string.m_cstring;
}

main函数调用如下所示:

String str1;
String str2 = "abcdefg";
String str3 = str1 + str2;
str1 += str2 += str3;
str1[0];
str1 = str2;
if(str1 > str2){
            
}

这个字符串封装功能内部维护一个c_cstring大致也有了string差不多的功能,内部进行了封装和抽取,对内存管理需要深入的认识。

仿函数

将一个对象按照函数一样来使用,其实是对象内部重载了(),外部调用就像函数调用一样,对比普通函数,它作为对象可以状态。

#include 
using namespace std;

class Sum {
    int m_age;
public:
    Sum(int age) :m_age(age) { }
    int operator()(int a, int b) {
        if (this->m_age > 10) {}
        else {}
        return a + b;
    }
};

int main() {
    Sum sum(20);
    
    //防函数调用
    cout << sum(10, 20) << endl;
    //运算符重载调用
    cout << sum.operator()(10, 20) << endl;

    return 0;
}

关于运算符的重载,有些运算符不能被重载,比如:

  • 对象成员访问运算符: .
  • 域运算符号:::
  • 三目运算符:?:
  • sizeof
    有些运算符只能重载为成员函数,比如:
  • 赋值运算符:** = **
  • 下标运算符:[]
  • 函数运算符号:()
  • 指针访问成员:->

你可能感兴趣的:(C++面向对象-运算符重载)