Featured image of post C++面向对象高级开发-Complex复数类的设计与实现

C++面向对象高级开发-Complex复数类的设计与实现

C++的类可以分为基于对象的类和面向对象的类,面向对象的类之间有继承、复合和委托的设计模式,通过对Complex类设计的实现,掌握相关的设计规范范式……

C++面向对象高级开发-Complex复数类的设计与实现

Notes

C++类分为:

  • Object Based(基于对象)
  • Object Oriented(面向对象)

基于对象:

  • 不带有指针成员的类:Complex
  • 带有指针成员的类:String

面对单一class的设计: 面向对象:

  • 继承(inheritance)
  • 复合(composition)
  • 委托(delegation)

面对多重class的设计:

  • 类与类之间的关系

设计规范

设计规范1:

函数在类体内定义完成,自动成为inline内联函数候选人 数据要放在private区

设计规范2:

防卫式(guard)声明

#ifndef __COMPLEX__
#define __COMPLEX__
……
#endif

设计规范3:

构造函数:

class complex {
public:
    complex (double r = 0, double i = 0) : re (r), im (i) {}    //初值列
    ...
private:
    double re, im;
    ...
}

若增加构造函数:complex() : re(0), im(0) {} 是不允许的,原因:默认的构造函数有默认初值。 Singleton模式:不允许被外界创建对象时,构造函数放在private区。

设计规范4:

若该函数内容不会改变,增加const关键字

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

设计规范5:

参数传递引用优先。若需保持引用对象不变,可增加const关键字。 complex& operator += (const complex&); 返回值传递同理。

设计规范6:

相同class的对象互为友元。 如:

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

int main(int argc, const char *argv[]) {
    complex c1(2,1);
    complex c2;

    c2.func(c1);
}

设计规范7:

  • 所有的成员函数都带有隐含参数this,this指调用者。
  • 传递者无需知道接收者是以reference形式接收
inline complex& __doapl(complex* ths, const complex& r) {
    ...
    return *ths; // *ths为传递者 inline complex&中,complex&为接收者
}
inline complex& complex::operator += (const complex& r) {
    return __doapl(this,r);
}

complex c1(2,1);
complex c2(5);
complex c3;
c2+=c1;
c3+=c2+=c1;

考虑到c3+=c2+=c1的表达式中,c2+=c1运算的结果必须为complex&才可继续与c3运算,所以,inline complex& complex::operator +=的返回值类型必须为complex&,而不可为void

  • 所有非成员函数都不含有隐含参数this。
inline complex operator + (const complex& x, const complex& y) {
    return complex(x.real()+y.real(), x.imag()+y.imag());
}

如上述非成员函数示例中,返回值为函数内创建,即为Local Object,函数执行结束,返回值被释放。所以,绝对不可以使用引用传递返回值,只能按值传递。如complex();为临时对象,生命周期只有当前行,当前行执行完毕,生命周期结束。

总结

总结:编写程序思考的步骤:

  1. 防卫式声明
  2. 设计复数类,考虑实部虚部数据放在私有private区。
  3. 对数据进行操作的函数。首先为无返回类型的构造函数,考虑参数默认值,考虑参数按值传递还是按引用传递。构造函数要使用初值列赋初值。
  4. 考虑设计为成员函数或非成员函数。成员函数写在class中。考虑参数传递和返回值类型。
  5. 设计函数时是否要加const。不改动数据加const。class内部函数为inline候选人。
  6. 非Local object返回值类型传引用。
  7. operator +设计为成员函数,功能受限。由于成员函数的操作符作用在左值,如对操作符<<重载时,使用写法应为c1 << cout;,有违于常规写法,所以此函数设计应考虑全局操作符重载。

Complex函数完整源码

Complex-Test.cpp

//
//  main.cpp
//  Complex
//
//  Created by Fa1c0n on 2020/2/17.
//  Copyright © 2020 Fa1c0n. All rights reserved.
//

#include <cstdlib>
#include "Complex.h"

using namespace std;

int main(int argc, const char * argv[]) {
    Complex c1(2, 1);
    Complex c2(4, 0);

    cout << c1 << endl;
    cout << c2 << endl;

    cout << c1+c2 << endl;
    cout << c1-c2 << endl;
    cout << c1*c2 << endl;
    cout << c1 / 2 << endl;
    cout << (c2 - 2) << endl;
    cout << (5 + c2) << endl;

    cout << conj(c1) << endl;
    cout << norm(c1) << endl;
    cout << polar(10, 4) << endl;

    cout << (c1 += c2) << endl;
    cout << (c1 -= c2) << endl;
    cout << (c1 *= c2) << endl;
    cout << (c1 /= c2) << endl;

    cout << (c1 == c2) << endl;
    cout << (c1 != c2) << endl;
    cout << (c1 == 2) << endl;
    cout << (c2 != 4) << endl;

    cout << +c2 << endl;
    cout << -c2 << endl;

    return EXIT_SUCCESS;
}

Complex.hpp

//
//  Complex.h
//  Complex
//
//  Created by Fa1c0n on 2020/2/17.
//  Copyright © 2020 Fa1c0n. All rights reserved.
//

#ifndef __COMPLEX_H__
#define __COMPLEX_H__
#include <iostream>
#include <cmath>

using namespace std;

class Complex;
Complex& __doapl(Complex& ths, const Complex& comp);
Complex& __doami(Complex& ths, const Complex& comp);
Complex& __doaml(Complex& ths, const Complex& comp);
Complex& __doadi(Complex& ths, const Complex& comp);

class Complex {
public:
    Complex(double real = 0, double imag = 0) : re(real), im(imag) {};
    double real() const {return re;}
    double imag() const {return im;}
    Complex& operator += (const Complex&);
    Complex& operator -= (const Complex&);
    Complex& operator *= (const Complex&);
    Complex& operator /= (const Complex&);
private:
    double re, im;
    friend Complex& __doapl(Complex*, const Complex&);
    friend Complex& __doami(Complex*, const Complex&);
    friend Complex& __doaml(Complex*, const Complex&);
    friend Complex& __doadi(Complex*, const Complex&);
};

inline ostream& operator << (ostream& os, const Complex& comp) {
    return os << "[" << comp.real() << ", " << comp.imag() << "]";
}

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

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

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

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

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

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

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

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

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

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

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

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

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

inline Complex operator / (const Complex& x, const Complex& y) {
    return Complex(x.real()/y.real(), x.imag()/y.imag());
}

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

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

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

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

inline Complex& __doami(Complex* ths, const Complex& comp) {
    ths->re -= comp.re;
    ths->im -= comp.im;
    return *ths;
}

inline Complex& Complex::operator -= (const Complex& comp) {
    return __doami(this, comp);
}

inline Complex& __doaml(Complex* ths, const Complex& comp) {
    ths->re *= comp.re;
    ths->im *= comp.im;
    return *ths;
}

inline Complex& Complex::operator *= (const Complex& comp) {
    return __doaml(this, comp);
}

inline Complex& __doadi(Complex* ths, const Complex& comp) {
    if (comp.re != 0 && comp.im != 0) {
        ths->re /= comp.re;
        ths->im /= comp.im;
    }
    return *ths;
}

inline Complex& Complex::operator /= (const Complex& comp) {
    return __doadi(this, comp);
}

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

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

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

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

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

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

inline Complex conj (const Complex& comp) {
    return Complex(comp.real(), -comp.imag());
}

inline double norm (const Complex& comp) {
    return comp.real()*comp.real()+comp.imag()*comp.imag();
}

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

#endif
/* Complex_h */