运算符重载

该教程是参照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对象之间转换了,可以彼此进行赋值。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值