complex类的定义

头文件的布局

#ifndef  __COMPLEX__
#define   __COMPLEX__
class complex { ... }; #endif

一定要采用防卫式声明,保证头文件不被重复包含。

类的两种形式

类的定义分为有指针成员的类和无指针成员的类。

下面介绍complex类实现无指针成员类的定义,string类实现有指针成员类的定义。

complex类的定义

class complex
{
public:
    complex (double r = 0, double i = 0)
        : re (r), im (i)
    { }
    complex& operator += (const complex&);
    double real () const { return re; }
    double imag () const { return im; }
private:
    double re, im;
    
    friend complex& __doapl (complex*, const complex&);
};

内联函数

有些函数直接定义在class body中定义,有些则在class body外定义。若函数定义在calss body中,则函数自动成为inline候选函数。定义在class body外的函数需要使用inline关键字建议编译器将其内联:

inline double
imag(const complex& x)
{
    return x.imag ();
}

访问级别

访问级别共三种:public,private,protected。

数据通常要设置成private属性,从而达到对外隐蔽的作用,函数一般设置public属性,从而可以作为接口被外部调用。假设我们定义了上面的复数类。

采用下面的方式获取复数的实部和虚部是正确的:

cout << c1.real();
cout << c1.imag();

但是采用下面的方式获取复数的实部和虚部时编译器将会报inaccessible的错误:

cout << c1.re;
cout << c1.im;

构造函数

complex (double r = 0, double i = 0)
        : re (r), im (i)
    { }

构造函数没有返回值也不需要返回值。

构造函数可以采用initialization list ,也是唯一可以采用这种初始化方式的函数,采用initialization list是一种高效的方式,推荐使用,而不要采用在构造函数内部再去初始化,这种方式效率低。

构造函数可以重载,但是下面这种重载的方式,编译器将会报has more than one default constructor的错误:

complex(double r = 0, double i = 0)
    : re(r), im(i)
        { }
complex() :re(0), im(0){}    

//调用时
complex c;

这是因为上面既定义了一个提供了默认参数的初始化,又提供了无参数的构造函数,实例化对象时将会产生歧义。

如果被构造函数放在private区:

private:
        
    complex(double r = 0, double i = 0)
        : re(r), im(i)
    { }

此时如果要实例化对象:

complex c1;
complex c2(2,1)

编译器会报:cannot access private member declared in class 'complex',说明将构造函数放在private区后将不能用来实例化对象。但是C++中有一种名为Singleton 的设计模式,就是将构造函数放在private区:

class A {
public:
    static A& getInstance();
    setup() { ... }
private:
    A();
    A(const A& rhs);
    ...
};
A& A::getInstance()
{
    static A a;
    return a;
}

常量成员函数 

double real () const { return re; }
double imag () const { return im; }

常量成员函数说明,在这个函数中不会修改变量的值,一般建议通常只要函数不会修改变量的值都定义成常量成员函数,这样也可以避免下面的错误:

//定义函数时
double real()  { return re; }
double imag()  { return im; }

//调用函数时
const complex c(2, 1);
cout << c.real() << endl;
cout << c.imag() << endl;

这种情况就是使用意图和定义的意图不一致。

参数传递

参数传递的方式有:传值、传引用。

推荐使用传引用的方式,因为这种传递方式本质长传递的是指针(4byte),传递效率高,但是如果参数占用1byte、2byte则也可以采用传值得方式,效率更高一些。

通过引用传参,变量的值在函数中被修改将导致连锁反应,即参数值也会随着改变,如果我们不想参数值在函数中改变,可以传const 引用。

complex& operator += (const complex&);

返回值传递

返回值传递的方式:传值、传引用。

一般推荐传引用,这种方式效率更高,但并不是绝对的,有些情况下不得不传递值。

//返回值传引用
complex& operator += (const complex&);
//返回值传值
double real () const { return re; }
double imag () const { return im; }

当然在返回引用时也可以添加const。

友元函数

//class body中声明
friend complex& __doapl (complex*, const complex&);

//class body 外定义
inline complex&
__doapl (complex* ths, const complex& r)
{
    ths->re += r.re;
    ths->im += r.im;
    return *ths;
}

友元函数能够自由的获取private成员。

友元函数破坏了类的封装性,但是相比于使用函数返回private成员的方式效率高。

相同class的object之间互为友元:

增加一个函数:

int func(const complex& param)
{ return param.re + param.im; }

调用时:

complex c1(2, 1);
complex c2;
cout<

操作符重载

在C++中操作符可以看成是一个函数,操作符重载可以分为两种形式,在calss body内的作为成员函数的重载,以及class body外作为全局函数的重载。

重载+=:

inline complex&
__doapl(complex* ths, const complex& r)
{
    ths->re += r.re;
    ths->im += r.im;
    return *ths;
}

inline complex&
complex::operator += (const complex& r)
{
    return __doapl (this, r);
}

//调用时
{
    complex c1(2,1);
    complex c2(5);
    c2 += c1;
}

类的每个成员函数都包含一个this指针,参数传递时不需要显示指出来,这个this指针指向当前调用类成员函数的对象。
注意上面的两个函数的返回值之所以采用引用的形式,是因为可能在使用时出现下面的调用形式:

c3 +=c2 += c1

重载+操作符:

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, double y)
{
    return complex (real (x) + y, imag (x));
}
inline complex
operator + (double x, const complex& y)
{
    return complex (x + real (y), imag (y));
}

//调用时
complex c2;
c2 = c1 + c2;
c2 = c1 + 5;
c2 = 7 + c1;

这里需要注意的是,上面的三个函数,决不能返回引用的形式,这是因为typename()将创建临时变量,不能用引用来接收函数中返回的局部变量。
typename()将在函数内部申请临时的存储空间,一旦程序运行到typename()所在行结束,这个临时的空间就不存在了。

定义取正取负重载操作符 

inline complex
operator + (const complex& x)
{
    return x;
}
inline complex
operator - (const complex& x)
{
    return complex (-real (x), -imag (x));
}

//调用时
complex c1(2,1);
complex c2;
cout << -c1;
cout << +c1;

这里不是加减号,是因为参与运算参数的个数只有1个,在这里是单目的取正和取负操作符。
注意取负函数不能返回引用形式的参数,这是因为它的返回值是局部变量。 

非成员函数的操作符重载 

inline bool
operator != (const complex& x,
const complex& y)
{
    return real (x) != real (y)
    || imag (x) != imag (y);
}
inline bool
operator != (const complex& x, double y)
{
    return real (x) != y || imag (x) != 0;
}
inline bool
operator != (double x, const complex& y)
{
    return x != real (y) || imag (y) != 0;
}

//调用时
complex c1(2,1);
complex c2;
cout << (c1 != c2);
cout << (c1 != 2);
cout << (0 != c2); 

重载<<:

#include 
ostream&
operator << (ostream& os, const complex& x)
{
    return os << '(' << real (x) << ','
    << imag (x) << ')';
}

<<是一个ostream对象,这里返回引用的形式是防止如下调用:

cout << c1 << conj(c1);

calss body外的各种定义

求共轭复数:

inline complex
conj (const complex& x)
{
    return complex (real (x), -imag (x));
}

取复数的实部和虚部:

inline double
imag(const complex& x)
{
    return x.imag ();
}
inline double
real(const complex& x)
{
    return x.real ();
}

//调用时
complex c1(2,1);
cout << imag(c1);
cout << real(c1);

定义在class body外即为全局作用域函数。

完整的复数类定义

#ifndef __MYCOMPLEX__
#define __MYCOMPLEX__

class complex; 
complex&
  __doapl (complex* ths, const complex& r);
complex&
  __doami (complex* ths, const complex& r);
complex&
  __doaml (complex* ths, const complex& r);


class complex
{
public:
  complex (double r = 0, double i = 0): re (r), im (i) { }
  complex& operator += (const complex&);
  complex& operator -= (const complex&);
  complex& operator *= (const complex&);
  complex& operator /= (const complex&);
  double real () const { return re; }
  double imag () const { return im; }
private:
  double re, im;

  friend complex& __doapl (complex *, const complex&);
  friend complex& __doami (complex *, const complex&);
  friend complex& __doaml (complex *, const complex&);
};


inline complex&
__doapl (complex* ths, const complex& r)
{
  ths->re += r.re;
  ths->im += r.im;
  return *ths;
}
 
inline complex&
complex::operator += (const complex& r)
{
  return __doapl (this, r);
}

inline complex&
__doami (complex* ths, const complex& r)
{
  ths->re -= r.re;
  ths->im -= r.im;
  return *ths;
}
 
inline complex&
complex::operator -= (const complex& r)
{
  return __doami (this, r);
}
 
inline complex&
__doaml (complex* ths, const complex& r)
{
  double f = ths->re * r.re - ths->im * r.im;
  ths->im = ths->re * r.im + ths->im * r.re;
  ths->re = f;
  return *ths;
}

inline complex&
complex::operator *= (const complex& r)
{
  return __doaml (this, r);
}
 
inline double
imag (const complex& x)
{
  return x.imag ();
}

inline double
real (const complex& x)
{
  return x.real ();
}

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, double y)
{
  return complex (real (x) + y, imag (x));
}

inline complex
operator + (double x, const complex& y)
{
  return complex (x + real (y), imag (y));
}

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, double y)
{
  return complex (real (x) - y, imag (x));
}

inline complex
operator - (double x, const complex& y)
{
  return complex (x - real (y), - imag (y));
}

inline complex
operator * (const complex& x, const complex& y)
{
  return complex (real (x) * real (y) - imag (x) * imag (y),
               real (x) * imag (y) + imag (x) * real (y));
}

inline complex
operator * (const complex& x, double y)
{
  return complex (real (x) * y, imag (x) * y);
}

inline complex
operator * (double x, const complex& y)
{
  return complex (x * real (y), x * imag (y));
}

complex
operator / (const complex& x, double y)
{
  return complex (real (x) / y, imag (x) / y);
}

inline complex
operator + (const complex& x)
{
  return x;
}

inline complex
operator - (const complex& x)
{
  return complex (-real (x), -imag (x));
}

inline bool
operator == (const complex& x, const complex& y)
{
  return real (x) == real (y) && imag (x) == imag (y);
}

inline bool
operator == (const complex& x, double y)
{
  return real (x) == y && imag (x) == 0;
}

inline bool
operator == (double x, const complex& y)
{
  return x == real (y) && imag (y) == 0;
}

inline bool
operator != (const complex& x, const complex& y)
{
  return real (x) != real (y) || imag (x) != imag (y);
}

inline bool
operator != (const complex& x, double y)
{
  return real (x) != y || imag (x) != 0;
}

inline bool
operator != (double x, const complex& y)
{
  return x != real (y) || imag (y) != 0;
}

#include 

inline complex
polar (double r, double t)
{
  return complex (r * cos (t), r * sin (t));
}

inline complex
conj (const complex& x) 
{
  return complex (real (x), -imag (x));
}

inline double
norm (const complex& x)
{
  return real (x) * real (x) + imag (x) * imag (x);
}

#endif   //__MYCOMPLEX__
View Code

转载于:https://www.cnblogs.com/xiaojianliu/articles/9483857.html

你可能感兴趣的:(complex类的定义)