运算符
运算符 | 建议使用 |
---|---|
所有一元运算符 | 成员函数 |
= 、( ) 、[ ] 、-> | 必须成员函数 |
+= 、-= 、/= 、*= 、^= 、&= 、%=……所有带=的 | 成员函数 |
二元运算符,- 、+ 、* 、/ | 友元函数 |
<< 、 >> | 必须友元函数 |
取反: //返回类型还是一个类对象
Point Point::operator-(){
x = -x;
y = -y;
return *this;
} //单目运算符无参数,操作数访问重载运算符的对象本身数据
双目运算符+:
String String::operator +(char *append_str){
String temp;
int templen;
templen = strlen(buffer)+strlen(append_str)+1;
if(templen > Max)
{
cout << "String is too large!" <<endl;
strcpy(temp.buffer, buffer);
return temp;
}
length = templen;
strcpy(temp.buffer, buffer);
strcat(temp.buffer, append_str);
return temp;
}
Complex Complex::operator+(int a){
Complex temp;
temp.real =real+a;
temp.imag =imag+a;
return temp;
}
++运算符:
Point Point::operator ++(){
return Point(++x,++y);
} //++x
Point Point::operator++(){
++x;
++y;
return *this;
}
Point Point::operator --(int){
return Point(x--,y--);
}
Point Point::operator--(int){
Point temp = *this;
x--;
y--;
return temp;
}
赋值运算符:
Student & Student::operator=(const Student &p){
if(this == &p)
return *this;
delete name;
name = new char[strlen(p.name)+1];
strcpy(name, p.name);
return *this;
}
下表运算符[]:
int &Vector4::operator[](int bi){ //定义下标运算符 [] 重载函数
if(bi<0||bi>=4){ //数组的边界检查
cout<<"Bad subscript!\n";
exit(1);
}
return v[bi];
}
调用运算符():
int &Mat::operator()(int r, int c){
return (*(m+r*col+c));
}
void operator()(string name){//重载方式不唯一
cout << name << endl;
} //调用 P1("zhangchuang");
友元函数重载+:friend Complex operator+(Complex a, Complex b);
Complex operator+(Complex a, Complex b){
Complex temp;
temp.real = b.real + a.real;
temp.imag = b.imag + a.imag;
return temp;
}
关系运算符:
bool operator==(Per &P){//重载==
if (m_name == P.m_name && m_A == P.m_A)
return true;
return false;
}
类型转换运算符:
operator double(){ return real; } //将对象强制转换为double类型
#include <iostream>
using namespace std;
class Complex
{
private:
double real, imag;
public:
Complex(double r=0, double i=0):real(r),imag(i){}
operator double(); //强制转换运算符
};
Complex::operator double()
{
cout << "Type changed to double" << endl;
return real;
}
int main()
{
Complex a(1.1, 2.2);
cout <<"显示准换" << (double)a << endl; //输出1.1
double n = 2 + a; //等价于 double n=2+c.operator double()
cout <<"隐式转换"<< n << endl; //输出3.1
return 0;
}
Matrix(const Matrix& a){
r = a.r;
j = a.j;
M = new int* [r];
for (int i = 0; i < r; i++)
M[i] = new int[j];
for (int i = 0; i < r; ++i)
for (int j = 0; j < a.j; j++)
M[i][j] = a.M[i][j];
}
#include <iostream>
using namespace std;
//左移运算符重载
class Person {
public:
int A;
int B;
Person(int a = 0, int b = 0) :A(a), B(b) {}
};
ostream& operator<<(ostream& out, Person& P) {
out << P.A << "," << P.B;
return out;
}
int main()
{
Person P1(1, 2);
cout << P1 << endl; //cout为标准的输出流对象
return 0;
}
重载是面向对象程序设计的基本特点之一。在面向对象程序中存在两种形式的重载:
1、函数重载:指在相同的作用域内,若干个参数特征不同的函数使用相同的函数名。
2、运算符重载:指同样的运算符施加于不同类型的操作数上,运算符的语义可以不同。
运算符重载是对已有的运算符赋予多重含义
必要性:C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)
实现机制:将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。编译系统对重载运算符的选择,遵循函数重载的选择原则。
规则和限制
可以重载C++中除下列运算符外的所有运算符:. .* :: ?:
只能重载C++语言中已有的运算符,不可臆造新的。
不改变原运算符的优先级和结合性。
不能改变操作数个数(单目或者双目运算符)。
经重载的运算符,其操作数中至少应该有一个是自定义类型。
成员函数重载运算符
class 类名{
//……
返回类型 operator 运算符(形参表)
//……
};
返回类型 类名::operator 运算符(形参表)
{
//函数体
}
调用
单目运算符重载
显式调用 :对象名.operator 运算符()
隐式调用 :重载的运算符 对象名
#include<iostream>
#include<iomanip>
using namespace std;
class Point
{
private:
int x, y;
public:
Point(int i= 0, int j = 0):X(i),y(j){}
Point operator -();//返回类型还是一个类对象
void Print(){
cout<<"x = "<< x << setw(5)<<"y="<<y<<endl;
}
};
Point Point::operator-() //单目运算符无参数,操作数访问重载运算符的对象本身数据
{
x = -x;
y = -y;
return *this;
}
int main()
{
Point ob1(1,2);
cout<<"ob1:"<<endl;
ob1.Print();
cout<<"-ob1:"<<endl;
ob1.operator-(); 显示调用
//ob = -ob1; 隐式调用
ob1.Print();
return 0;
}
双目运算符重载
显式调用 :对象名.operator 运算符(参数)
隐式调用 :对象名 重载的运算符 参数(左边为对象本身,由this指针指向;右边为参数)
#include <iostream>
#include <string.h>
using namespace std;
const int Max = 20;
class String
{
private:
char buffer[Max];
int length;
public:
String(char *in_str);
String();
String operator +(char *append_str);
void showstring();
};
String::String(char *in_str)
{
strcpy(buffer, in_str);
length = strlen(buffer);
}
String::String()
{
length = 0;
}
String String::operator +(char *append_str)
{
String temp;
int templen;
templen = strlen(buffer)+strlen(append_str)+1;
if(templen > Max)
{
cout << "String is too large!" <<endl;
strcpy(temp.buffer, buffer);
return temp;
}
length = templen;
strcpy(temp.buffer, buffer);
strcat(temp.buffer, append_str);
return temp;
}
void String::showstring()
{
cout << buffer <<endl;
}
int main()
{
String title((char*)"C/C++ ");
title = title + (char*)"Program"; //隐式调用
//title = title.operator+("Program"); //显式调用,不加char*会出现警告
title.showstring();
return 0;
}
重载++、- -运算符
“+ +”和“- -”运算符是单目运算符,分前缀和后缀两种。
类名 operator ++() //前缀方式
类名 operator ++(int) //后缀方式
类名 operator —() //前缀方式
类名 operator —(int) //后缀方式
#include<iostream>
using namespace std;
class Point
{
public:
Point(){}
Point(int xx,int yy):x(xx),y(yy){}
Point operator ++();
Point operator ++(int); //后置是int型的变量,而非写数字0
Point operator --();
Point operator --(int);
void display(){cout<<"("<<x<<","<<y<<")"<<endl;}
private:
int x;
int y;
};
Point Point::operator ++()
{
return Point(++x,++y);
}
/*
Point Point::operator++()
{
++x;
++y;
return *this;
}
*/
Point Point::operator ++(int)
{
return Point(x++,y++);
}
Point Point::operator --()
{
return Point(--x,--y);
}
Point Point::operator --(int)
{
return Point(x--,y--);
}
/*
Point Point::operator--(int)
{
Point temp = *this;
x--;
y--;
return temp;
}
*/
int main()
{
Point p1(1,2);
++p1;
cout<<"++p1=";p1.display();
p1++;
cout<<"p1++=";p1.display();
--p1;
cout<<"--p1=";p1.display();
p1--;
cout<<"p1--=";p1.display();
return 0;
}
/*
++p1=(2,3)
p1++=(3,4)
--p1=(2,3)
p1--=(1,2)
*/
重载赋值运算符=
通常情况下,默认的赋值运算符函数可以完成赋值任务(逐位复制)。
但在某些特殊情况下,如类中有指针类形式,就不能进行直接相互赋值。
指针悬挂问题:
未重载赋值运算符时,执行两个对象(有名字指针)P2 =P1,两个对象的name指针指向了同一个空间,当两个对象生存期结束时,系统将调用析构函数释放空间。但是因为只有一个空间,所以只能释放一次,另一个指针所指的空间就不存在了,产生了指针悬挂。
Matrix& Matrix::operator =(const Matrix& a)//要重载=号,不重载就是浅拷贝
{
if (M != NULL)
{
for (int i = 0; i < j; i++)
delete[]M[i];
delete[]M;
}
r = a.r;
j = a.j;
M = new int* [r];
for (int i = 0; i < r; i++)
M[i] = new int[j];
for (int i = 0; i < r; ++i)
for (int k = 0; k < j; k++)
M[i][k] = a.M[i][k];
return *this;
}
例2
Student & Student::operator=(const Student &p)
{
if(this == &p)
return *this;
delete name;
name = new char[strlen(p.name)+1];
strcpy(name, p.name);
return *this;
}
重载下标运算符[]
当程序变得更为复杂时,有时必须重载数组下标运算符[ ]
重载下标运算符“[ ]”时,返回一个 int 型的引用,可使重载的“[ ]”用在赋值语句的左边,因而在 main 函数中,ve[i] 可以出现在赋值运算符的任何一边,使编程更灵活。
- 重载下标运算符[ ]的一个优点是,可以增加C++中数组检索的安全性,防止数组越界。
- 重载下标运算符[ ]时,返回一个int的引用,可使重载的“[ ]”用在赋值语句的左边,因而在main函数中,v[i]可以出现在赋值运算符的任何一边,使编制程序更灵活了。 ```cpp 返回类型 类名∷operator[] (形参) { //函数体 }
include
using namespace std; class Vector4 { private: int v[4]; public: Vector4(int a1,int a2,int a3,int a4){ v[0]=a1;v[1]=a2;v[2]=a3;v[3]=a4; } int &operator; //声明下标运算符 [] 重载函数 };
int &Vector4::operator{ //定义下标运算符 [] 重载函数 if(bi<0||bi>=4){ //数组的边界检查 cout<<”Bad subscript!\n”; exit(1); } return v[bi]; }
int main(){
Vector4 ve(0,1,2,3);
cout<<ve[2]<<endl; //ve[2] 相当于 ve.operator
ve[3]=ve[2];
cout<<ve[3]<<endl;
ve[2]=22;
cout<<ve[2];
return 0;
}
<a name="OYysG"></a>
# 重载函数调用运算符“( )”
```cpp
返回类型 类名::()(形参)
{
//函数体
}
#include <iostream>
using namespace std;
class Mat
{
private:
int *m;
int row,col;
public:
Mat(int, int);
int &operator()(int, int);
};
Mat::Mat(int r, int c)
{
row = r;
col = c;
m = new int[row*col];
for(int i = 0; i < row*col; i++)
{
*(m+i) = i;
}
}
int &Mat::operator()(int r, int c)
{
return (*(m+r*col+c));
}
int main()
{
Mat aM(10, 10);
cout << aM(3, 4) <<endl; 返回3行4列的元素
aM(3, 4) = 35;
cout << aM(3, 4) <<endl;
return 0;
}
友元函数重载运算符
用友元函数重载运算符时,若运算符是单目的,则参数表中有一个操作数,如果运算符是双目的,则参数表中有两个操作数。
friend <函数类型>operator<重载的运算符>(<形参>) //单目运算符重载
{
//函数体
}
friend <函数类型>operator<重载的运算符>(<形参1,形参2>) //双目运算符重载
{
//函数体
}
友元函数重载运算符实现复数的加、减运算
#include <iostream>
using namespace std;
class Complex
{
private:
double real,imag;
public:
Complex(double r = 0.0, double i = 0.0);
void Print();
friend Complex operator+(Complex a, Complex b);
friend Complex operator-(Complex a, Complex b);
};
Complex::Complex(double r, double i)
{
real = r;
imag = i;
}
Complex operator+(Complex a, Complex b)
{
Complex temp;
temp.real = b.real + a.real;
temp.imag = b.imag + a.imag;
return temp;
}
/*
用成员函数重载运算符“+”。
Complex Complex::operator+(int a)
{
Complex temp;
temp.real =real+a;
temp.imag =imag+a;
return temp;
}
*/
Complex operator-(Complex a, Complex b)
{
Complex temp;
temp.real = b.real - a.real;
temp.imag = b.imag - a.imag;
return temp;
}
void Complex::Print()
{
cout <<real;
if(imag > 0)
cout << "+";
if(imag != 0)
cout << imag << "i" <<endl;
}
int main()
{
Complex c1(1.1, 2.2), c2(3.3, 4.4),total;
total = c1 + c2;
total.Print();
total = c1 - c2;
total.Print();
return 0;
}
成员函数重载运算符与友元函数重载运算符比较
双目运算符,成员函数重载运算符带有一个参数,而友元函数重载运算符带有两个参数;单目运算符,成员函数重载运算符不带参数,而友元函数重载运算符带一个参数。
双目运算符一般可以被重载为友元运算符函数或成员运算符函数,下面的情况必须使用友元函数。
C++的大部分运算符既可以说明为成员函数重载运算符,也可以说明为友元函数重载运算符。在选择时主要取决于实际情况和程序员的习惯。
#include <iostream>
#include <string>
using namespace std;
/********* Begin *********/
class Matrix//矩阵类的声明
{
private:
int r, j;
int** M;
public:
Matrix(int x, int y){
r = x;
j = y;
M = new int* [x];
for (int i = 0; i < x; i++)
M[i] = new int[j];
}
~Matrix(){
for (int i = 0; i < r; i++)
delete[]M[i];
delete[]M;
}
void Fill(int value){
for (int i = 0; i < r; i++)
for (int k = 0; k < j; k++)
M[i][k] = value;
}
void Set(int r, int c, int value){
M[r][c] = value;
}
int Get(int r, int c){
return M[r][c];
}
Matrix(const Matrix& a)//拷贝构造函数
{
r = a.r;
j = a.j;
M = new int* [r];
for (int i = 0; i < r; i++)
M[i] = new int[j];
for (int i = 0; i < r; ++i)
for (int j = 0; j < a.j; j++)
M[i][j] = a.M[i][j];
}
void Print()//输出
{
for (int i = 0; i < r; i++) {
for (int k = 0; k < this->j; k++)
cout<< M[i][k]<<" ";
cout << endl;
}
}
Matrix operator+(Matrix& m2);
Matrix operator-(Matrix& m2);
Matrix operator*(Matrix& m2);
Matrix& operator =(const Matrix& a);
};
//矩阵类的定义
Matrix Matrix::operator+(Matrix& m2)//实现矩阵加法
{
Matrix m3(r,j);
for (int i = 0; i < r; i++)
for (int k = 0; k < j; k++)
m3.M[i][k] = this->M[i][k] + m2.M[i][k];
return m3;
}
Matrix Matrix::operator-(Matrix& m2)//实现矩阵减法
{
Matrix m3(r, j);
for (int i = 0; i < r; i++)
for (int k = 0; k < j; k++)
m3.M[i][k] = this->M[i][k] - m2.M[i][k];
return m3;
}
Matrix Matrix::operator*(Matrix& m2)//实现矩阵乘法
{
Matrix m3(this->r, m2.j);
m3.Fill(0);
for (int i = 0; i < this->r; i++)
for (int k = 0; k < m2.j; k++)
for (int l = 0; l < this->j; l++)
m3.M[i][k]+= this->M[i][l] * m2.M[l][k];
return m3;
}
Matrix& Matrix::operator =(const Matrix& a)//要重载=号,不重载就是浅拷贝
{
if (M != NULL)
{
for (int i = 0; i < j; i++)
delete[]M[i];
delete[]M;
}
r = a.r;
j = a.j;
M = new int* [r];
for (int i = 0; i < r; i++)
M[i] = new int[j];
for (int i = 0; i < r; ++i)
for (int k = 0; k < j; k++)
M[i][k] = a.M[i][k];
return *this;
}
int main()
{
int i, j;
cin >> i >> j;
Matrix m1(i, j), m2(i, j), m3(j, i);
m1.Fill(1);
m2.Fill(2);
m3.Fill(0);
for (int s = 0; s < i; s++) {
for (int c = 0; c < j; c++) {
if (s == c)
m3.Set(s, c, s + 1);
}
}
//m3.Print();
cout << "m1 + m2 :" << endl;
(m1 + m2).Print();
cout << "m1 - m2 :" << endl;
(m1 - m2).Print();
cout << "m1 * m3 :" << endl;
(m1 * m3).Print();
m2 = m1 = m3;
m1.Print();
m2.Print();
}
例题:定义一个分数类,并为其重载>>和<<运算符,使得分数对象可以整体输入输出;实现分数类中的运算符重载(分子和分母均为整型)即分数的加、减、乘、除的运算(运算后要求化简)
#include <iostream>
using namespace std;
class CFraction
{
private:
int nume; // 分子
int deno; // 分母
public:
CFraction(int nu = 0, int de = 1) :nume(nu), deno(de) {}
void simplify();
friend istream& operator >>(istream& input, CFraction&);
friend ostream& operator <<(ostream& output, CFraction&);
CFraction operator+(const CFraction& c);
CFraction operator-(const CFraction& c);
CFraction operator*(const CFraction& c);
CFraction operator/(const CFraction& c);
CFraction operator+();
CFraction operator-();
bool operator>(const CFraction& c);
bool operator<(const CFraction& c);
bool operator==(const CFraction& c);
bool operator>=(const CFraction& c);
bool operator<=(const CFraction& c);
};
// 分数化简
void CFraction::simplify()
{
int m, n, r;
m = abs(deno);
n = abs(nume);
while (r = m % n) // 求m,n的最大公约数
{
m = n;
n = r;
}
deno /= n; // 化简
nume /= n;
if (deno < 0) // 将分母转化为正数
{
deno = -deno;
nume = -nume;
}
}
istream& operator >>(istream& input, CFraction& c)
{
input >> c.nume >> c.deno;
return input;
}
/*重载复数运算符
ostream& operator<<(ostream& out, complex1& c)
{
out << c.real;
if (c.iamg > 0)
out << "+";
out << c.iamg << "i" << endl;
return out;
}*/
ostream& operator <<(ostream& output, CFraction& c)
{
output << "(" << c.nume << "/" << c.deno << ")";
return output;
}
CFraction CFraction::operator+(const CFraction& c)
{
CFraction t;
t.deno = c.deno * deno;
t.nume = deno * c.nume + c.deno * nume;
t.simplify();
return t;
}
CFraction CFraction::operator-(const CFraction& c)
{
CFraction t;
t.deno = c.deno * deno;
t.nume = c.deno * nume - deno * c.nume;
t.simplify();
return t;
}
CFraction CFraction::operator*(const CFraction& c)
{
CFraction t;
t.deno = c.deno * deno;
t.nume = nume * c.nume;
t.simplify();
return t;
}
CFraction CFraction::operator/(const CFraction& c)
{
CFraction t;
t.deno = c.nume * deno;
t.nume = nume * c.deno;
t.simplify();
return t;
}
CFraction CFraction::operator+()
{
CFraction t;
t.deno = deno;
t.nume = nume;
t.simplify();
return t;
}
CFraction CFraction::operator-()
{
CFraction t;
t.deno = deno;
t.nume = -nume;
t.simplify();
return t;
}
bool CFraction::operator>(const CFraction& c)
{
int t1_nume, t1_deno, t2_nume, t2_deno;
t1_nume = deno * c.nume;
t1_deno = c.deno * deno;
t2_nume = c.deno * nume;
t2_deno = c.deno * deno;
if (t1_nume > t2_nume)
return true;
else
return false;
}
bool CFraction::operator<(const CFraction& c)
{
int t1_nume, t1_deno, t2_nume, t2_deno;
t1_nume = deno * c.nume;
t1_deno = c.deno * deno;
t2_nume = c.deno * nume;
t2_deno = c.deno * deno;
if (t1_nume < t2_nume)
return true;
else
return false;
}
bool CFraction::operator==(const CFraction& c)
{
int t1_nume, t1_deno, t2_nume, t2_deno;
t1_nume = deno * c.nume;
t1_deno = c.deno * deno;
t2_nume = c.deno * nume;
t2_deno = c.deno * deno;
if (t1_nume == t2_nume)
return true;
else
return false;
}
bool CFraction::operator>=(const CFraction& c)
{
int t1_nume, t1_deno, t2_nume, t2_deno;
t1_nume = deno * c.nume;
t1_deno = c.deno * deno;
t2_nume = c.deno * nume;
t2_deno = c.deno * deno;
if (t1_nume >= t2_nume)
return true;
else
return false;
}
bool CFraction::operator<=(const CFraction& c)
{
int t1_nume, t1_deno, t2_nume, t2_deno;
t1_nume = deno * c.nume;
t1_deno = c.deno * deno;
t2_nume = c.deno * nume;
t2_deno = c.deno * deno;
if (t1_nume <= t2_nume)
return true;
else
return false;
}
int main()
{
CFraction c1, c2, t, t1, t2;
cout << "请输入分数(格式 xx xx)" << endl;
cin >> c1;
cout << "c1 = " << c1 << endl;
cout << "请输入分数(格式 xx xx)" << endl;
cin >> c2;
cout << "c2 = " << c2 << endl;
t = c1 + c2;
cout << "c1 + c2 = " << t << endl;
t = c1 - c2;
cout << "c1 - c2 = " << t << endl;
t = c1 * c2;
cout << "c1 * c2 = " << t << endl;
t = c1 / c2;
cout << "c1 / c2 = " << t << endl;
t = c1;
cout << "t = " << t << endl;
t = -c1;
cout << "-t = " << t << endl;
cout << c1;
if (c1 > c2) cout << " > 并且 ";
if (c1 < c2) cout << " < 并且";
if (c1 == c2) cout << " == ";
if (c1 >= c2) cout << " >= ";
if (c1 <= c2) cout << " <= ";
cout << c2;
system("pause");
return 0;
}
class Per {
public:
Per(string name,int a):m_name(name),m_A(a){}
bool operator==(Per &P)//重载==
{
if (m_name == P.m_name && m_A == P.m_A)
return true;
return false;
}
bool operator!=(Per& P)//重载!=
{
if (m_name == P.m_name && m_A == P.m_A)
return false;
return true;
}
private:
string m_name;
int m_A;
};
int main()
{
Per P1("张闯", 18);
Per P2("小茜", 18);
Per P3("张闯", 18);
if (P1 == P2)
cout << "P1等于P2" << endl;
else
cout << "P1不等于P2" << endl;
if (P1 != P2)
cout << "P1不等于P2" << endl;
else
cout << "P1等于P2" << endl;
return 0;
}
class Per
{
public:
int m_A;
string m_name;
Per(int a,string name):m_A(a),m_name(name){}
void operator()(string name)//重载方式不唯一
{
cout << name << endl;
}
int operator()(int a, int b)
{
return a + b;
}
};
int main()
{
Per P1(18,"张闯");
P1("zhangchuang");
int tem=P1(10, 20);
cout << "tem=" << tem << endl;
system("pause");
return 0;
}
运行结果:
zhangchuang
30