运算符重载的基本概念
有需求:要用来对象之间的运算,比如两个复数的对象的相加:a+b(a.r+b.r、a.v+b.v)
目的:扩展c++中提供的适用范围,可以作用于对象
实质:函数重载。可以写成普通函数的形式和成员函数的形式,使用的时候,就相当于对函数的调用。
运算符可以被多次重载,根据操作数的类型决定调用什么函数。
重载为成员函数时,参数个数为运算符目数减一
重载为普通函数时,参数个数为运算符目数
例子
#include <iostream>
using namespace std;
class Complex{
public:
double real, imag;
Complex(double r=0.0, double i=0.0):real(r), imag(i){}
Complex operator-(const Complex &c);
void Print();
};
void Complex::Print() {
cout<<real<<" "<<imag<<endl;
}
Complex operator+(const Complex &a, const Complex &b)
{
return Complex(a.real+b.real, a.imag+b.imag);
}
Complex Complex::operator-(const Complex &c) {
return Complex(real-c.real, imag=c.imag);
}
int main(){
Complex a(1,2);
Complex c(2,3);
Complex b = c+a;
cout<<"b(c+a) is:"<<endl;
b.Print();
cout<<"a-c is:"<<endl;
(a-c).Print();
return 0;
}
b(c+a) is:
3 5
a-c is:
-1 3
赋值运算符重载
只能重载为成员函数
浅拷贝和深拷贝
直接用等于号,那么两个对象指向同一个地方,如果其中一个对象delete掉,那么另一个对象在消亡的时候,也会delete一次,会导致程序崩溃,而且如果其中一个对象指向另一个地方,那么这个对象就会delete,另一个对象指向的就没有东西了。。。。因此要再写一次等号的重载
考虑返回值,如果返回一个void,那么a=b=c就不行了,如果返回一个String对象的化,在c++中,赋值运算符的返回值是引用,因此,我们要返回那个值的引用
这里还有个问题,就是,复制构造函数的问题了。。。所以要编写一个复制构造函数
上面两个的使用例子:
#include <iostream>
#include <cstring>
using namespace std;
class String{
private:
char *str;
public:
String():str(new char[1]){str[0]=0;}
String(char* s){
cout<<" in transform construction "<<endl;
str = new char[strlen(s)+1];
strcpy(str, s);
}
const char*c_str(){return str;};
String &operator = (const char *s);
String &operator = (const String &s);
String(const String &s){
cout<<" in copy construction"<<endl;
str = new char[strlen(s.str)+1];
strcpy(str, s.str);
}
~String(){delete[] str;};
};
String& String::operator=(const char *s) {
cout<<" in operator = "<<endl;
delete[]str;
str = new char[strlen(s)+1];
strcpy(str, s);
return *this;
}
String& String::operator=(const String &s) {
cout<<" in operator String"<<endl;
if(this==&s) return *this;
delete [] str;
str = new char[strlen(s.str)+1];
strcpy(str, s.str);
return *this;
}
void copys(String s){
cout<<"in copy fun"<<endl;
}
int main()
{
String s1;
s1 = "Hello world";
cout<<s1.c_str()<<endl;
String s2 = "Good luck";
cout<<s2.c_str()<<endl;
s1 = s1;
copys(s1);
cout<<strlen(s1.c_str())<<endl;
return 0;
}
in operator =
Hello world
in transform construction
Good luck
in operator String
in copy construction
in copy fun
11
运算符重载友元
一般情况下,将运算符重载为类的成员函数比较好,但是有时,成员函数不能满足使用要求,重载为普通函数不能访问类的私有变量,所以就选择将运算符重载为友元
可变长数组类的实现(自己加的pop_back)
#include <iostream>
#include <cstring>
using namespace std;
class CArray{
int size;
int *ptr;
public:
CArray(int s=0);
CArray(CArray &a);
~CArray();
void push_back(int v);
CArray & operator = (const CArray&a);
int length(){return size;}
int& operator[](int i);
void pop_back();
};
int& CArray::operator[](int i) {
return ptr[i];
}
CArray::CArray(int s):size(s) {
if(s==0)
ptr = NULL;
else
ptr = new int[s];
}
CArray::CArray(CArray &a) {
if(!a.ptr){
ptr = NULL;
size = 0;
return ;
}
ptr = new int[a.size];
size = a.size;
memcpy(ptr, a.ptr, sizeof(int)*a.size);
return ;
}
CArray::~CArray() {
if(ptr){
delete[]ptr;
}
}
CArray& CArray::operator=(const CArray &a) {
if(ptr == a.ptr) return *this;
if(a.ptr == NULL){
if(ptr!=NULL) delete[]ptr;
ptr=NULL;
size = 0;
return *this;
}
if(size<a.size){
if(ptr) delete[]ptr;
ptr = new int[a.size+1];
}
memcpy(ptr, a.ptr, sizeof(int)*a.size);
size = a.size;
return *this;
}
void CArray::push_back(int v) {
if(ptr){
int*tmpPtr=new int[size+1];
memcpy(tmpPtr, ptr, sizeof(int)*size);
delete [] ptr;
ptr = tmpPtr;
}
else{
ptr = new int[1];
}
ptr[size++] = v;
}
void CArray::pop_back() {
ptr[size-1]=ptr[size];
size--;
}
int main()
{
CArray a;
for (int i = 0; i < 5; ++i) {
a.push_back(i);
}
CArray a2,a3;
a2 = a;
for (int i = 0; i < a.length(); ++i) {
cout<<a2[i]<<" ";
}
a2 = a3;
for (int i = 0; i < a2.length(); ++i) {
cout<<a2[i]<<endl;
}
cout<<endl;
a[3]=100;
CArray a4(a);
for (int i = 0; i < a4.length(); ++i) {
cout<<a4[i]<<" ";
}
cout<<endl;
a4.pop_back();
for (int i = 0; i < a4.length(); ++i) {
cout<<a4[i]<<" ";
}
return 0;
}
0 1 2 3 4
0 1 2 100 4
0 1 2 100
流插入运算符和流提取运算符的重载
#include <iostream>
using namespace std;
class CStudent{
public:
int nAage;
};
ostream&operator<<(ostream & o, const CStudent & s){
o<<s.nAage;
return o;
}
int main()
{
CStudent s;
s.nAage = 5;
cout<<s<<"hello";
return 0;
}
5hello
这里注意,在重载运算符的时候,可以将传入的参数设置为对象的引用,这样可以节省时间和空间的开销,如下例,没有调用复制构造函数:
#include <iostream>
using namespace std;
class people{
private:
int eyes;
public:
people(){eyes=2;}
friend void set_eyes(const people & p, int i);
people(const people & p) {
cout<<"in copy fun"<<endl;
eyes = p.eyes;
}
void printf()const{cout<<eyes;}
};
void set_eyes(const people & p, int i){
p.printf();
};
int main()
{
people p;
set_eyes(p, 3);
return 0;
}
类型转换运算符
#include <iostream>
using namespace std;
class Complex{
double real, imag;
public:
Complex(double r=0, double i=0):real(r), imag(i){}
operator double(){return real;}
};
int main()
{
Complex c(1,2);
cout<<(double)c<<endl;
double a = 2+c;
cout<<a<<endl;
return 0;
}
自增自减运算符
前置作为一元运算符重载
后置作为二元运算符重载
#include <iostream>
using namespace std;
class CDemo{
private:
int n;
public:
CDemo(int i=0):n(i){}
CDemo & operator++();
CDemo operator ++(int);
operator int(){return n;}
friend CDemo &operator--(CDemo & );
friend CDemo operator--(CDemo &, int);
};
CDemo& CDemo::operator++() {
++n;
return *this;
}
CDemo CDemo::operator++(int k) {
CDemo tmp(*this);
n++;
return tmp;
}
CDemo & operator--(CDemo& d){
d.n--;
return d;
}
CDemo operator--(CDemo& d, int k)
{
CDemo tmp(d);
d.n--;
return tmp;
}
int main()
{
CDemo d(5);
cout<<(d++)<<",";
cout<<d<<",";
cout<<(++d)<<",";
cout<<d<<endl;
cout<<(d--)<<",";
cout<<d<<",";
cout<<(--d)<<",";
cout<<d<<endl;
return 0;
}
注意:
1、不允许定义新的运算符
2、符合日常习惯
3、不改变运算符的优先级
4、以下运算符不能被重载:”.”, “.*”, “::”, “?:”, sizeof:
5、重载运算符()、[]、->、=时,必须声明为成员函数