C++友元函数、运算符重载(C++ primer,P381)

主要介绍以下几点:

  • 类友元函数的创建方式;
  • 运算符重载的限制;
  • 如何重载运算符(以 + 为例);
  • 运算符重载与友元函数;
  • ( << )运算符的重载;

类的友元函数

通常来说,外部实现对类私有成员的访问,只能通过类的公有方法,然而友元提供了另一用方法。

  • 友元函数

  • 友元类

  • 友元成员函数

    创建类的友元

class A
{
	private:
		...
	public:
		...
		friend void func(...);
		//注意,和类的const成员函数不一样,
		//友元函数属于正常的函数,不能声明成const型
		//friend void func(...) const;
};

//func不是类的成员,定义时不需要A::func()
//func定义时无需加friend前缀
	void func(...){
		...
	}

定义友元函数时需要注意以下两点:

 - 无需(类名::函数名)的形式去定义,因为友元不是类的成员;
 - 定义时无需加friend前缀;

所以,也不能用成员运算符调用友元函数

那么问题就来了,都有类的公有方法了,为什么多此一举搞一个友元函数?
在运算符重载那一部分,会详细介绍友元函数的具体用法。

重载运算符的限制

  • 重载后的运算符,必须要有一个操作数是用户定义的类型(防止用户为标准类型重载运算符);
  • 重载运算符不能违反运算符原有的语法(不能将 + 重载成 - ,将 * 重载成 /);
  • 不能创建新的运算符;
  • 一些特殊运算符不能重载;

不能重载的运算符如下:

	sizeof			:	计算空间运算
	.				:	成员运算
	.*				:	成员指针运算
	::				:	作用域运算
	?:				:	条件运算
	typeid			:	RTTI运算符
	四个强制类型转换运算符

仅能通过成员函数进行重载的运算符(重载的函数必须是类的成员函数)

	=			:	赋值运算
	()			:	函数调用运算
	[]			:	下标运算
	->			:	通过指针访问类成员运算

运算符重载

假设我有一个类Vector,类Vector表示xoy平面的向量(Vector仅有两个私有变量x和y)

class Vector{
privatr:
	double x;
	double y;
public:
	//构造函数与析构函数,具体内容就不写了
	Vector();
	Vector(double xx, double yy);
	~Vector();
};

Vector a = {1.0, 2.0}, b = {1.5, 2.5};

上面用Vector创建了两个向量a和b,现在我想做向量的加法,使:

Vector c = a + b;

此时就需要重载“+”运算符。
具体重载方法如下:

class Vector{
...
public:
	Vector & operator+(const Vector v) const;
}

Vector & Vector::operator+(const Vector v) const {
	Vector c;
	c.x = x + v.x;
	c.y = y + v.y;
	return c;
}

此时需要注意,c = a + b重载运算符“+”,使用的是运算符函数,其实际形式是

 // c = a + b与下面的形式等价:
  c = a.operator+( b );

所以该函数,隐式的使用a(因为调用了它的方法),显式的使用对象b(被作为参数传递);
同理,乘法运算 c = a * 2.0也可以实现,只需将参数的形式变化一下即可。
那么,如果想要算 c = 2.0 * a 呢? 2.0只是一个double常量,它怎么调用“它的方法”呢?
这里就需要使用上面的友元函数了。
因为友元函数不是类的成员函数,非成员函数不是由对象调用的,它所有的参数都是显式参数,所以, c = 2.0 * a如果调用非成员函数的运算符重载,则编程下面这种形式:

c = operator* (2.0, a);

所以重载“*”运算需要定义两种重载函数:

class Vector{
	private:
	...
	public:
		...
		Vector & operator*(const Vector v) const;
		friend Vector & operator*(double n, const Vector v);
		//或者将友元换成下面这种成员函数也可以
		Vector & operator*(double n, const Vector v) const {
			//此处实际是调用第一个函数
			return v * n;
		}
}

重载 <<

如果我们用下面这个成员函数重载<<,运行下列指令会发生什么?

void operator<<(std::ostream & os, const Vector &v);
...
Vector a = {1.0, 2.0};
std::cout << a << "a" << a << "a" << std::endl;

很明显,cout << a后返回的是void,再执行 void << "a"会报错。此时,我们需要按照下面这种方式重载<<.

std::ostream & operator<<(std::ostream & os, const Vector &v);
...
Vector a = {1.0, 2.0};
std::cout << a << "a" << a << "a" << std::endl;

这样,cout << a后返回的还是一个cout,再执行 cout << “a” ……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值