运算符重载
运算符重载又称为操作符重载,可以为运算符增加一些新的功能,全局函数和成员函数都支持运算符重载,我们通过具体的实例来演示下,我们声明一个Point类,并且定义需要通过运算符重载的类。
#pragma once
#include <iostream>
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 <iostream>
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 <iostream>
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
有些运算符只能重载为成员函数,比如: - 赋值运算符:** = **
- 下标运算符:[]
- 函数运算符号:()
- 指针访问成员:->
网友评论