(二)const、参数传递、返回值传递、类设计中的细节

class complex
{
public:
	complex(double r = 0, double i = 0):re(r), im(i){}
	complex() : re(0), im(0){}
	//不能通过编译,会有二义性
	//当构建一个无参的complex对象时,第一个构造函数有缺省值,故二者均为候选函数,编译器无法确定到第调用哪个
	complex& operator += (const complex&);//传加const的引用,传入的数据不能被改变
	double real() const{return re;}//不修改数据时添加const
	double image() const{return im;}
private:
	double re, im;
	friend complex& __doapl(complex*, const complex&);
};

const

  • 在函数只使用数据而不修改数据时,在函数参数列表后加上const
    • 加const表示该函数保证不修改传入的数据。
    • 如果不加const,使用者对const对象调用该函数时,编译器会报错。因为不加const表示该函数可能会修改数据,而const对象无法被修改。
//无论real和image是否为const,均可以调用成功
complex c1(2, 1);
cout<< c1.real();
cout<< c1.image();

//real和image加了const才可以调用成功
const complex c2(2, 1);
cout<< c2.real();
cout<< c2.image();

参数传递

pass by value
  • 把value全部传过去,value有多大,传的包就有多大。传的动作就是把value压到函数的栈中去。
  • double类型的数据是4个字节就传4个字节,如果是100个字节也就传递100个字节
  • 尽量不要传值,传引用
pass by reference
  • 引用在底部就是指针,传引用就相当于传指针一样快
  • 传加const的引用,表示虽然传的是引用,但是不能修改数据

返回值传递

  • 尽量返回引用
  • 不能返回引用的情况:一个函数的操作结果
    • 如果放在现有位置,则可以返回引用
    • 如果要新创建一个变量存储结果则返回值。

相同class的各个objects互为friends

class complex
{
public:
	complex(double r = 0, double i = 0):re(r), im(i){}
	int func(const complex& param)
	{ return param.re + param.im;}
private:
	double re, im;
};

{
	complex c1(2, 1);
	complex c2;
	c2.func(c1);
}

运算符重载

成员函数运算符重载
  • 任何成员函数都有一个隐藏的this指针,指针指向调用者。
//传入的第一个参数是一个指针,返回的是指针所指的对象,但是返回值的声明却是引用
//这种形式是正确的
inline complex&
__doapl(complex* ths, const complex& r)
{
	...
	return *ths;
}

inline complex& 
complex:: operator += (const complex& r)
{
	return __doapl(this, r);
}
  • 传引用的好处:传递者无需知道接收者是用什么形式来接收的
inline complex&//接收端用引用来接收,速度更快
__doapl(complex* ths, const complex& r)
{
//传入的左操作数是一个指针,返回的是处理后的对象的引用
//传递者无需知道接收端是以什么形式来接收的
	...
	return *this;
}
inline complex&
complex::operator += (const complex& r)//为什么返回引用
{
	return __doapl(this, r);//传入的是this指针
}
  • 对+=的重载为什么返回引用,返回void可以吗
    • 返回void,对于没有连续赋值的情况完全适用
    • 返回引用,可以满足连续赋值的情况
    • 当使用者可能会连续使用该重载运算符时,要做更多的设计
{
	complex c1(2, 1);
	complex c2(5);
	
	c2 += c1;
	c3 += c2 += c1;//只有+=重载后返回引用,才可以这样使用
非成员函数运算符重载
  • +的重载
    • 不能返回引用,只能返回值,为什么
      • 因为加的结果是一个新的值,需要新的空间来存储
      • 返回引用绑定的是一个局部变量,一旦函数结束会被释放,会留下巨大的隐患
    • 不是成员函数
      • 可以是类对象加内置类型,也可以是内置类型加类对象
  • typename():表示创建临时对象,typename是待创建对象的类型
inline complex
operator + (const complex& x, const complex& y)
{
	return complex(real(x) + real(y), imag(x) + umag(y));//创建临时对象 
}
  • 对输出运算符<<,只能重载为非成员函数
    • cout是一个ostream对象,可以先把cout理解为屏幕,输出就是将<<的右边数据写入到cout中
    • cout会连续输出,所以重载<<要返回对ostream的引用
#include <iostream.h>
ostream& 
operator << (ostream& os, const complex& x)
{
	return os<<'('<<real(x)<<','
			 <<imag(x)<<')';
}

标准库中的complex类的设计过程

  1. 写防卫式的常数定义
  2. 写class的头
  3. 思考复数应该具有的数据类型,将它们放在private中
  4. 思考类内要有哪些函数
    4.1 构造函数,接受哪些参数,是否有默认值,传值还是传引用,列表初始化,函数体(如分配内存,打开一个窗口,打开一个文件等)
    4.2运算符重载,成员函数还是非成员函数,参数传递,返回类型
    4.3读取数据的函数,函数是否加const
  5. 在类外写类中声明函数的实现
    5.1 写操作符重载接口,先写函数全名,成员函数默认运算符左边是this所指的对象,考虑传入参数是否传引用,传入参数是否为const,返回类型是否为引用,是否加inline
    5.2 写接口的实现,是否需要调用辅助函数
  6. 重载输出运算符
    6.1 输入输出运算符不是成员函数,因为cout在运算符左侧,类对象在运算符右侧
    6.2 ostream传引用,被输出的对象不会被修改,加const
    6.3 cout会被改变,函数不是const函数
    6.4 使用ostream要引入头文件,可以在使用前引入所需的头文件,不一定全部在整个文件的头(最好是在文件头)
    6.5 为了可以连续使用该运算符<<,返回类型设为引用而不是void
    6.6 写输出复数的格式

类的设计总结

  1. 数据一定是private
  2. 参数尽可能的传引用,根据实际要求判断是否加const
  3. 返回值尽可能的传引用
  4. 类中的函数应该加const的都要加
  5. 构造函数尽量使用列表初始化
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值