運算符重載
運算符重載又稱為操作符重載,可以為運算符增加一些新的功能,全局函數(shù)和成員函數(shù)都支持運算符重載,我們通過具體的實例來演示下,我們聲明一個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實現(xiàn)如下:
#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調(diào)用如下:
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;
//以下兩個調(diào)用等價
p1 += p2;
p1.operator+=(p2);
//以下兩個調(diào)用等價
cout << p1;
operator<<(cout,p1);
注意,運算符重載最好跟系統(tǒng)的用法靠近,比如前++和后++的重載,以及考慮到const對象等。重載cout函數(shù)不能放到成員函數(shù)實現(xiàn),因為cout在對象前,最好聲明成類的友元函數(shù),便于訪問成員變量的值。下面我們自己再維護一個String類,實現(xiàn)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函數(shù)調(diào)用如下所示:
String str1;
String str2 = "abcdefg";
String str3 = str1 + str2;
str1 += str2 += str3;
str1[0];
str1 = str2;
if(str1 > str2){
}
這個字符串封裝功能內(nèi)部維護一個c_cstring大致也有了string差不多的功能,內(nèi)部進行了封裝和抽取,對內(nèi)存管理需要深入的認識。
仿函數(shù)
將一個對象按照函數(shù)一樣來使用,其實是對象內(nèi)部重載了(),外部調(diào)用就像函數(shù)調(diào)用一樣,對比普通函數(shù),它作為對象可以狀態(tài)。
#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);
//防函數(shù)調(diào)用
cout << sum(10, 20) << endl;
//運算符重載調(diào)用
cout << sum.operator()(10, 20) << endl;
return 0;
}
關于運算符的重載,有些運算符不能被重載,比如:
- 對象成員訪問運算符: .
- 域運算符號:::
- 三目運算符:?:
- sizeof
有些運算符只能重載為成員函數(shù),比如: - 賦值運算符:** = **
- 下標運算符:[]
- 函數(shù)運算符號:()
- 指針訪問成員:->