写在前面

最近正好有时间, 系统的学习一下C++中的面向对象思想, 实现一下基本的复数类, 主要参考了B站侯捷老师的C++课程(​​《C++面向对象高级编程(上)-基于对象&面向对象》​​), 有兴趣的小伙伴们可以去学习一下, 需要有一定的C++面向对象基础, 前面几节介绍了复数类的创建, 以及类的分文件编写时候需要注意的一些细节, 重点讲解了操作符重载这部分内容, 相当于是一个复习与巩固.

鉴于课程开始介绍过使用类模板创建一个复数类, 但是并没有完整实现, 下面我用之前学过的类模板的内容, 搞出来一个使用类模板创建的复数类.

代码

分文件编写, 头文件中包含类的声明与实现, 构造函数、成员函数的类外实现.

运行环境
MacOS 11.3
g++ -std=c++11

complex_by_template.h

// 防卫式声明
#ifndef __COMPLEX__
#define __COMPLEX__
// ----- 前置声明 -----

template<typename T>
class complex;
// 标准库函数: do assignment plus
template<typename T>
complex<T>& __doapl (complex<T> *ths, const complex<T>& r);

template<typename T>
inline complex<T>&
__doapl(complex<T>* ths, const complex<T>& r)
{
ths->re += r.re;
ths->im += r.im;
return *ths;
}
// ----- 类的声明 -----
// 采用模板
template<typename T>
class complex
{
public:
// 构造函数(函数名要与类名相同)
complex (T r=0,T i=0): re (r), im (i)
{ }
complex& operator += (const complex&);
T real () const {return re;}
T imag () const {return im;}
private:
T re, im;
// 友元
friend complex& __doapl<> (complex *ths, const complex& r);
};

// 使用内联函数加快编译速度
template<typename T>
inline T real (const complex<T>& r)
{
return r.real();
}

template<typename T>
inline T imag (const complex<T>& r)
{
return r.imag();
}

template<typename T>
inline complex<T>&
complex<T>::operator += (const complex<T>& r)
{
return __doapl(this, r);
}
#endif

用类模板实现复数类的时候需要注意以下几点:

  1. 友元在类外实现时必须先进行类的声明, 然后编写全局函数, 最后进行类的实现, 类的实现中需要进行友元的声明, 并且需要加上空模板的参数列表(否则会产生链接错误);
  2. 成员函数的类外实现均需要加上类模板定义;
  3. 养成写参数列表的习惯.

complex_by_template_test.cpp

#include <iostream>
#include "complex_by_template.h"

using namespace std;

// 格式化输出复数
// 重载 << 运算符
template<typename T>
ostream&
operator << (ostream& os, const complex<T>& x)
{
if (imag(x)<0)
return os << real(x) << '-' << -imag(x) <<'i';
else
return os << real(x) << '+' << imag(x) << 'i';
}

void test1(){
complex<int> c1(-3,-3);
complex<int> c2(3,2);
c2 += c1;
cout<<c2<<endl;
}

int main(int argc, char const *argv[])
{
test1();
return 0;
}

输出:

0-1i

小结

注意一下类模板的一些实现细节, 就能得心应手了, 其实不是很复杂.