该教程是参照C++入门经典写的一个学习笔记,仅供参考。
运算符重载
运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
探索运算符重载
首先我们创建一个Counter类
#include<iostream>
class Counter
{
public:
Counter();
~Counter();
int getValue() const{return value;}
void setValue(int x){value=x;}
private:
int value;
};
Counter::Counter():value(0){}
Counter::~Counter(){}
int main()
{
Counter c;
std::cout<<"the value of c is "<<c.getValue()<<"\n";
system("pause");
return 0;
}
不同于内置的类型,如int类型。Counter对象不能递增,递减,相加和赋值,不能使用其他运算符操作它,显示其值也不容易。
重载递增运算符
下面我i们将利用运算符重载来消除这种缺陷
例如我们来为Counter类重载递增运算符++
#include<iostream>
class Counter
{
public:
Counter();
~Counter();
int getValue() const{return value;}
void setValue(int x){value=x;}
void increment(){++value;}
const Counter& operator++();
private:
int value;
};
Counter::Counter():value(0){}
Counter::~Counter(){}
const Counter& Counter::operator++()
{
++value;
return *this;
}
int main()
{
Counter c;
std::cout<<"the value of c is "<<c.getValue()<<"\n";
c.increment();
std::cout<<"the value of c is "<<c.getValue()<<"\n";
++c;
std::cout<<"the value of c is "<<c.getValue()<<"\n";
Counter a=++c;
std::cout<<"the value of a is "<<a.getValue();
std::cout<<" and c: "<<c.getValue()<<"\n";
system("pause");
return 0;
}
运算结果为:
the value of c is 0
the value of c is 1
the value of c is 2
the value of a is 3 and c: 3
- 如果Counter对象分配了内存,就必须重写复制构造函数。就这里而言,默认复制构造函数就可以。
- 注意到返回的是Counter引用,这避免了创建额外的临时对象。==这是一个const引用,因为使用对象的函数不修改其值。==这个地方我也不是太懂。
重载后缀运算符
- 问题来了,递增运算符有前缀和后缀两个版本,都是++。无法通过成员函数名来区分他们。怎么办呢?
- 办法是给成员函数operator()添加一个int参数。在函数体内,不会使用这个参数,它只用于表明该函数定义的是后缀运算符。
- 前缀运算符++x是先修改变量的值,再在表达式中使用修改后的值;而后缀运算符先返回变量的值,然后才对变量递增或递减。
- 为此,在重载的成员函数中,必须先创建一个临时对象,用于存储原始值,一边对原始值进行递增。返回的将是原始对象,因为后缀运算符要求使用原始值,而不是递增后的值。
- 必须按值(而不是按引用)返回该临时对象,否则函数返回时它将不再在作用域中 。
#include<iostream>
class Counter
{
public:
Counter();
~Counter();
int getValue() const{return value;}
void setValue(int x){value=x;}
void increment(){++value;}
const Counter& operator++(); //prefix
const Counter operator++(int); //postfix
private:
int value;
};
Counter::Counter():value(0){}
Counter::~Counter(){}
const Counter& Counter::operator++() //prefix
{
++value;
return *this;
}
const Counter Counter::operator++(int)
{
Counter temp(*this);
++value;
return temp;
}
int main()
{
Counter c;
std::cout<<"the value of c is "<<c.getValue()<<"\n";
c++;
std::cout<<"the value of c is "<<c.getValue()<<"\n";
++c;
std::cout<<"the value of c is "<<c.getValue()<<"\n";
Counter a=++c;
std::cout<<"the value of a is "<<a.getValue();
std::cout<<" and c: "<<c.getValue()<<"\n";
a=c++;
std::cout<<"the value of a is "<<a.getValue();
std::cout<<" and c: "<<c.getValue()<<"\n";
system("pause");
return 0;
}
程序运行结果如下所示
the value of c is 0
the value of c is 1
the value of c is 2
the value of a is 3 and c: 3
the value of a is 3 and c: 4
重载加法运算符
递增运算符属于单目运算符,这意味着它只需要一个操作数。加法运算符(+)是双目运算符,将两个操作数相加,这给重载带来了新的挑战。
#include<iostream>
class Counter
{
public:
Counter();
Counter(int initialValue);
~ Counter();
int getValue() const {return value;}
void setValue(int newValue){value=newValue;}
Counter operator+(const Counter&);
private:
int value;
};
Counter:: Counter():value(0)
{
}
Counter::Counter(int initialValue):value(initialValue)
{
}
Counter::~ Counter()
{
}
Counter Counter::operator+(const Counter &rhs)
{
return Counter(value+rhs.getValue());
}
int main()
{
Counter alpha(4),beta(13),gamma;
gamma=alpha+beta;
std::cout<<"alpha: "<<alpha.getValue()<<std::endl;
std::cout<<"beta: "<<beta.getValue()<<std::endl;
std::cout<<"gamma: "<<gamma.getValue()<<std::endl;
system("pause");
return 0;
}
程序运行结果如下:
alpha: 4
beta: 13
gamma: 17
对运算符重载的限制
- 不能重载用于内置类型的运算符
- 不能改变运算符的优先级和目数(单目,双目或三目)
- 另外,不能创建新运算符。
赋值运算符
#include<iostream>
class Tricycle
{
public:
Tricycle();
~Tricycle();
int getSpeed() const{return *speed;}
void setSpeed(int newSpeed){*speed=newSpeed;}
Tricycle operator=(const Tricycle&);
private:
int *speed;
};
Tricycle::Tricycle()
{
speed=new int;
*speed=5;
}
Tricycle::~Tricycle()
{
}
Tricycle Tricycle::operator=(const Tricycle &rhs)
{
if(this==&rhs) //为避免对象将值赋给自己,如果不预防这种情况,自赋值时可能导致对象将分配给自己的内存释放,这要等到要赋值
return *this; //右操作数时,内存已经被释放了,无法访问getSpeed()成员函数了
delete speed; //由于左边的对象已存在,并且分配了内存,为避免内存泄漏,必须将这些内存释放,然后再重新分配内存
speed=new int;
*speed=rhs.getSpeed();
return *this;
}
int main()
{
Tricycle wichita;
std::cout<<"wichita's speed: "<<wichita.getSpeed()<<std::endl;
wichita.setSpeed(6);
std::cout<<"wichita's speed: "<<wichita.getSpeed()<<std::endl;
Tricycle dallas;
std::cout<<"dallas's speed: "<<dallas.getSpeed()<<std::endl;
wichita=dallas;
std::cout<<"wichita's speed: "<<wichita.getSpeed()<<std::endl;
std::cout<<"dallas's speed: "<<dallas.getSpeed()<<std::endl;
system("pause");
return 0;
}
程序运算结果如下:
wichita’s speed: 5
wichita’s speed: 6
dallas’s speed: 5
wichita’s speed: 5
dallas’s speed: 5
转换运算符
如果试图将一个内置类型(int 或 unsigned short)变量赋给一个用户定义的类对象,怎么实现呢?
这是通过创建一个转换运算符来实现的,它是一个构造函数,接收一个int参数并创建一个Counter对象
如下代码:
#include<iostream>
class Counter
{
public:
Counter();
~Counter();
Counter(int newValue);
int getValue() const {return value;}
void setValue(int newValue){value=newValue;}
private:
int value;
};
Counter::Counter():value(0)
{
}
Counter::Counter(int newValue):value(newValue)
{
}
Counter::~Counter()
{
}
int main()
{
int beta=5;
Counter alpha=beta;
std::cout<<"alpha: "<<alpha.getValue()<<std::endl;
system("pause");
return 0;
}
程序运行结果:
alpha: 5
最重要的修改位于第8行和第18-20行。添加了一个带有int参数的构造函数重载版本。
编译器见到27行将一个int变量赋给Counter对象时,便知道调用该构造函数。
int()运算符
前一个项目演示了如何将内置类型变量赋给对象,还可以将对象赋给内置类型对象,如下所示:
#include<iostream>
class Counter
{
public:
Counter();
~Counter();
Counter(int newValue);
int getValue() const {return value;}
void setValue(int newValue){value=newValue;}
operator unsigned int(); //声明了转换运算符,没有返回值
private:
int value;
};
Counter::Counter():value(0)
{
}
Counter::Counter(int newValue):value(newValue)
{
}
Counter::operator unsigned int()
{
return(value);
}
Counter::~Counter()
{
}
int main()
{
Counter alpha(19);
int beta=alpha;
std::cout<<"beta: "<<beta<<"\n";
system("pause");
return 0;
}
程序输出结果如下:
beta: 19
注意到转换运算符没有指定返回值,但实际上它们返回了一个转换后的值。
现在编译器知道如何再int变量和Counter对象之间转换了,可以彼此进行赋值。