一步一步写出c++不带指针类实例(标准库complex部分)
总共有19步
流程:
- 首先先养成防卫式习惯,在头文件中加入下面三行,防止重复包含(行2,3,19)
- 然后写出主体(行4,5,18)
- 考虑下这个复数需要什么数据,当然这个数据应该放在私有部分(private)。
复数有实部虚部,可得出private变量的定义(行15,16) - 接下来考虑需要什么函数来实现,这些函数当然需要操作在复数身上,然后
函数是对外发表的,所以放在public里面(行7,行8) - 首先任何一个class都有构造函数,然后构造函数的语法是什么?
构造函数名称与class名称相同,没有返回类型。接着,一个构造函数应该接收什么参数?
在这个例子中,有实部虚部,我们就应该有实部虚部的参数,然后我们就考量要不要默认值。 - 我们还要考虑这个函数的传递是按值传递还是按引用传递?
这个函数中传值或者传引用区别不大,所以随便选择一个 - 还得想到构造函数有个很特别的语法—初始列,一般最好运用初始列
- 然后考虑构造函数还需要干什么,这个例子已经不需要什么操作,在别的地方可能要在构造函数中分配一些内存,开个窗口,或者开个文件等等(行9,10)
- 接下来考虑这个class要实现什么功能,在这个例子中,我们实现复数的加法。
对于该函数有两种选择,一种是成为成员函数,另一种则是非成员函数,这两种选择都可以,这里我们选择第一种。(行12) - 还需要准备什么函数呢?需要两个函数去取得private里面实部和虚部的值。对于一个函数,我们考虑是否要加const,在这里只是要取实虚部的值,所以要加const保证安全。(行13,14)
- 接下来在class本体外实现复数的加法,先把函数首部除参数之外的东西写出来(complex::operator += ),然后再思考参数是什么?
+=,一定有个左边有个右边,由于该函数是一个成员函数,是作用在左边身上,所以左边就有一个隐藏的参数放进来,不知道在参数列表第几个位置,反正就是一定有,所以在参数里面就写右边就好。(行12) - 首先我们要考虑传引用,所以加&,那要不要加const?+=是左边动,右边不动,所以要加const。
然后考虑返回值类型,显而易见+=得到左边的是一个复数,所以是complex类型,那么要不要传引用?由于左边本来就存在,不是在函数里面才定义的,所以可以传引用。
由于这个函数是在class本体之外,为了提高效率,所以加个inline,至于最终会不会变成内联函数,这个就要看编译器 - 然后补充完整函数主体(行22-33)
- 然后我们多了三个加法,复数+复数,复数+实数,实数+复数,是在本体外,为什么?(行42-54)
如果放在class里面,就只能实现一种加法 - 接着考虑输出功能,举个例子,要输出complex c1(9,8)。
这里可能需要<<操作符重载,操作符<<只能作用在左边,那么就意味着得是c1 << cout;为了避免这种情况,我们需要重载运算符,实现cout << c1;(行56-61) - 由于该重载函数不是成员函数,所以不需要complex::,由于该函数要实现cout << c1,所以左边是cout,左边参数就得是“cout类型”,查手册得cout属于class ostream(得包含头文件< iostream >,同理右边是complex。
然后考虑传引用,class complex和class ostream都是很大东西,传引用速度快。然后考虑要不要加const,右边作用于左边,右边肯定不变,加const,那么左边呢?
左边会改变,状态会改变,所以不能加const - 接着考虑返回值对于cout << c1这种情况,可以设置为void,但是对于cout << c1 << endl这种情况呢?
- 当cout << c1执行完毕之后,应该传回一种想cout这种东西让<< endl继续执行,那cout是什么东西,ostream,所以返回值最好设置为ostream。ostream是本来就有的,所以可以传引用
- 最后补全函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61本体
class complex
{
public:
complex (double r = 0, double i = 0)
: re (r), im (i)
{ }
complex& operator += (const complex&);
double real const () { return re;} //函数完整,是inline
double imag const () { return im;} //inline
private:
double re, im;
friend complex& _doapl (complex*, const complex);
}
本体外
inline complex&
_doapl(complex* ths, const complex & r) //左边变,右边不变,所以左边不要const
{
ths->re += r.re;
ths->im += r.im;
return *ths;
}
inline complex&
complex::operator += (const complex & r)
{
return _doapl (this, r); //让_doapl实现加法
}
inline complex //不能传引用
operator + (const complex& x, const complex& y)
{
return complex(real(x) + real(y),
imag(x) + imag(y)); //类名称+小括号创建临时对象
}//复数+复数
inline complex
operator + (const complex& x, const complex& y)
{
return complex(real(x) + y,
imag(y));
}//复数+实数
inline complex
operator + (const complex& x, const complex& y)
{
return complex(x + real(y),
imag(y));
}//实数+复数
ostream&
operator << (ostream& os, const complex & x)
{
return os << '(' << real(x) << imag(x) << ')';
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 GreenHatHGのBlog!
评论