目录
加号运算符重载:
对于一般数据类型的数据运算,计算机是可以进行运算的,但是如果操作数是一些我们自己定义的数据类型,那么计算机就不知道怎么处理了,这时候就需要我们自己写个运算符重载的函数,对运算符进行重载,说直白点,就是手动添加一种自定义类型运算方式。
举个例子:我们创建一个类,这个类有两个成员变量。
class Info
{
public:
int a;
int b;
};
int main()
{
Info Exp1;
Info Exp2;
Info Exp3;
Exp1.a = 1;
Exp1.b = 2;
Exp2.a = 3;
Exp2.b = 4;
return 0;
}
我们先创建两个对象,并赋予初值。这里如果我们想创建一个新的对象,这个对象的第一个成员变量等于前两个对象的第一个成员变量相加;这个对象的第二个成员变量等于前两个对象的第二个成员变量相加我们可以这样操作:
class Info
{
public:
Info Add(Info& Exp1)
{
Info tmp;
tmp.a = Exp1.a + a;
tmp.b = Exp1.b + b;
return tmp;
}
void show()
{
cout << a << endl;
cout << b << endl;
}
int a;
int b;
};
int main()
{
Info Exp1;
Info Exp2;
Info Exp4;
Exp1.a = 1;
Exp1.b = 2;
Exp2.a = 3;
Exp2.b = 4;
Exp4 = Exp1.Add(Exp2);
Exp4.show();
return 0;
}
这里我们引入一个新的知识点:运算符重载,它的关键字是operator+1个符号。它的用法是将上面的Add函数函数名换成operator+就可以利用Exp1+Exp2来代替Exp1.Add(Exp2);。
总的来说就是Exp1.Add(Exp2)等价于Exp1.operator+(Exp2)等价于Exp1+Exp2;
这种运算符重载是利用成员函数进行运算符重载,我们也可以利用全局函数进行运算符重载:
成员函数示例如下:
class Info
{
public:
Info operator+(Info& Exp1)
{
Info tmp;
tmp.a = Exp1.a + a;
tmp.b = Exp1.b + b;
return tmp;
}
void show()
{
cout << a << endl;
cout << b << endl;
}
int a;
int b;
};
int main()
{
Info Exp1;
Info Exp2;
Info Exp3;
Exp1.a = 1;
Exp1.b = 2;
Exp2.a = 3;
Exp2.b = 4;
Exp3 = Exp1 + Exp2;
Exp3.show();
return 0;
}
全局函数示例如下:
class Info
{
public:
void show()
{
cout << a << endl;
cout << b << endl;
}
int a;
int b;
};
Info operator+(Info& Exp1,Info&Exp2)
{
Info tmp;
tmp.a = Exp1.a + Exp2.a;
tmp.b = Exp1.b + Exp2.b;
return tmp;
}
int main()
{
Info Exp1;
Info Exp2;
Info Exp3;
Exp1.a = 1;
Exp1.b = 2;
Exp2.a = 3;
Exp2.b = 4;
Exp3 = Exp1 + Exp2;
Exp3.show();
return 0;
}
左移运算符重载
左移运算符就是C++中输出关键字cout后面的<<,我们需要能设计一个输出自定义类型的左移运算符。这里要注意,我们加号运算符的重载可以利用成员函数重载,但是我们的左移运算符不能通过成员函数重载,只能通过全局函数重载。因为作为成员函数,我们调用时是创建出来的对象是左操作数,而我们想要的是cout是左操作数,这是不可能实现的。
下面是利用全局函数来做<<运算符重载:
class Info
{
//要访问里面的私有成员,所以要加friend关键字
friend ostream& operator<<(ostream&, Info);
public:
Info()
{
a = 10;
b = 10;
}
private:
int a;
int b;
};
//这里返回引用,因为只能有一个cout
ostream& operator<<(ostream& cout, Info S)
{
cout << S.a<< " " << S.b;
return cout;
}
int main()
{
Info S;
//因为cout后面还可能有输出,所以返回一个cout
cout << S<<endl;
return 0;
}
加加运算符重载
加加运算符重载有几个注意事项:
1.我们要用占位参数int来区分两个operator++函数的区别;
2.前置加加要返回引用,因为会变的要保证一直是一个相同的数,主要用于解决多次操作而操作的不是同一个数的问题。
3.后置加加返回值,因为它创建的是临时变量,我们也不能对临时变量进行引用返回。并且实际中后置加加操作式必须为可修改左值,即不能同时多次后置加加。
下面是两个例子:
“++”操作符重载:
class INT
{
friend ostream& operator<<(ostream& , INT );
public:
INT()
{
a = 0;
}
//前置++
INT& operator++()
{
a++;
return *this;
}
//后置++
INT operator++(int)
{
INT tmp = *this;
a++;
return tmp;
}
private:
int a;
};
ostream& operator<<(ostream& cout, INT p)
{
cout << p.a;
return cout;
}
int main()
{
INT b;
cout << b++ << endl;
cout << b << endl;
return 0;
}
“--”操作符重载:
class INT
{
friend ostream& operator<<(ostream& , INT );
public:
INT()
{
a = 5;
}
//前置--
INT& operator--()
{
a--;
return *this;
}
//后置--
INT operator--(int)
{
INT tmp = *this;
a--;
return tmp;
}
private:
int a;
};
ostream& operator<<(ostream& cout, INT p)
{
cout << p.a;
return cout;
}
int main()
{
INT a;
int b = 5;
cout << --(--b)<< endl;
cout << b << endl;
cout << --(--a) << endl;
cout << a << endl;
return 0;
}
赋值运算符重载
因为我们使用原来的等号将一个对象赋值给另一个对象会遇到深拷贝和浅拷贝问题,当时我们的解决思路是直接拷贝时在堆区开辟新一块空间,这里我们直接重载赋值运算符。
class Info
{
public:
//构造函数
Info(int a)
{
Stu = new int(a);
cout << *Stu << endl;
}
//运算符重载,返回本身
Info& operator=(Info& p2)
{
this->Stu = new int(*(p2.Stu));
return *this;
}
//析构函数
~Info()
{
delete Stu;
Stu = NULL;
}
//输出函数
void show()
{
cout << *Stu << endl;
}
private:
int* Stu;
};
int main()
{
Info p1(18);
Info p2(20);
p1 = p2;
p1.show();
return 0;
}
比较运算符重载
比较运算符重载和前面类似。这里我才注意到C++中的字符串类型可以直接比较....
这里举个例子,重载比较运算符“==”号:
class Info
{
friend bool operator==(Info& , Info& );
public:
Info(string _name, int _id)
{
name = _name;
id = _id;
}
private:
string name;
int id;
};
bool operator==(Info& Stu1, Info& Stu2)
{
if (Stu1.id == Stu2.id && Stu1.name == Stu2.name)
return true;
else
return false;
}
int main()
{
Info Stu1("梁",312100);
Info Stu2("梁", 312100);
if (Stu1 == Stu2)
{
cout << "Y" << endl;
}
else
{
cout << "N" << endl;
}
return 0;
}
函数调用符重载
函数调用符就是调用函数后面的那个小括号,而这个运算符也是可以发生重载。重载后和函数调用很相似!具有很强大的功能和灵活性!
下面我们写个演示案例:
class Print
{
public:
void operator()(string name)
{
cout << name<<endl;
}
};
int main()
{
Print print;
print("梁");
Print()("梁");//匿名对象,用完这行后立即销毁!
return 0;
}