C++ 面向对象高级开发 -- complex 类的实现

1. Object Based(基于对象) vs. Object Oriented(面向对象)

Object Based: 面对的是单一class的设计;

Object Oriented:面对的是多重classes的设计,class 和 class 之间的关系。

classes 的两个经典分类:

  • class without pointer members -- complex
  • class with pointer members -- string

2. Header (头文件)

  2.1 防卫式声明

  2.2 把 complex 的实部和虚部写成模板类

  2.3 inline

inline 关键字是对编译器的建议。建议把某个函数定义为内联函数。实际上,是否定义为内联函数,由编译器决定。

定义在类内的函数,都是 “提议” 为内联函数。

  2.4 访问级别

所有数据成员都应该是private;

供外部使用的函数成员都应该是public,只供类内使用的函数成员可以是private;

  2.5 构造函数

complex (double r = 0, double i = 0)
    : re (r), im (i)    // initialization list(初值列,初始值)
{}
complex (double r = 0, double i = 0) {
    re =  r;
    im = i;        
}

上述是 2 种形式的构造函数,其结果都是对 re 和 im 进行赋值。但是,使用 initialization list 的代码效率更高,更彰显编程素养

  2.6 不需要析构函数

complex 类没有指针成员,因此不必使用析构函数。

  2.7 构造函数可以有很多个 -- overloading

下图所示,由于构造函数 (1) 的形参全部具有默认值,所以重载函数 (2) 会造成调用混乱。

而 real() 函数,编译器根据其返回值类型,形参类型和数量,定义了一个独一无二的函数名称(右下角所示)。

 

  2.8 构造函数为private权限

构造函数为private,即不允许外界创建对象。

举例子,一个设计模式,singleton,只允许该类创建一个对象。通过类内的静态函数创建对象。

  2.9 const member functions(常量成员函数)

若 real() 和 imag() 函数都没有加 const 关键字,如下面2种使用方式,左边是成立的,右边却不成立。原因在于,c1 是个 const 变量,若其调用 real(), real() 告诉编译器可以修改 c1 的值,出现矛盾,报错。

  2.10 返回值传递: return by value vs. return by reference( to const )

返回值优先考虑传引用。

什么情况下可以返回引用?

若返回的变量A是在函数内创建,函数结束后,栈内存释放,变量A销毁。此时便不可以返回A的引用。

  2.11 参数传递: by value vs. by reference( to const )

  2.12 friend 友元

complex 类认可 _doapl() 是它的友元函数,则在该函数内部可直接访问 complex 类的 private 数据成员。

相同 class 的各个 objects 互为友元,因此如下函数成立。

 

  2.13 操作符重载 -- 类内成员函数

在 complex 类内重载 += 运算符。其中,c1 作为重载运算符实参,对应的形参为 const 的引用类型。this 指针是类内成员函数的隐藏形参,此时 this 指针指向重载运算符的调用者,即 c2 . 

 

关于返回值的语法分析

重要概念:传递者无需知道接收者是以 reference 形式接收

如下,举两个例子:

  1. 函数 _doapl() ,返回值为 complex&,是接收者;函数内 return *this ,*this 作为传递者,  并非引用类型。
  2. 符号重载函数 += 的调用方式为  c2 += c1; 。实参 c1 为传递者,传值;形参 const complex & r 作为接收者,是引用类型。

对于  c2 += c1;  ,符号重载函数的返回值可以为 void;

对于  c3 += c2 += c1; ,符号重载函数的返回值必须为 complex&。此时,c1 先加 c2,返回 complex & 类型的右值。之后调用该右值的符号重载函数,与 c3 相加。 

  2.14 符号重载函数 -- 全局函数

操作符 << 的重载,只能定义为全局函数。原因如下,

 cout << conj(c1); ,操作符 << 只能作用在左边的 cout 上。cout 是输出流对象,无法在其类定义中添加操作符 << 的重载函数。因此,只能将操作符 << 重载函数定义为全局函数。

操作符 << 重载函数的实现:

  • cout 是 ostream 类型的对象;
  • 形参优先使用传引用;
  • 形参不能使用 const,因为往 os 中传值,会改变 os 的状态;
  •  cout << conj(c1); ,返回类型可以为 void;
  •  cout << c1 << conj(c1); ,返回类型必须为 ostream,且优先考虑返回引用。该语句的调用顺序为, cout << c1,返回 ostream 类型的右值。调用该右值的 << 重载函数输出 conj(c1).

注意事项总结

  1. 构造函数使用 initialization list;
  2. 函数是否定义为const;
  3. 函数参数尽量使用&,const;
  4. 函数返回值尽量使用&,const;
  5. 数据成员为private;
原文地址:https://www.cnblogs.com/gdut-gordon/p/12303279.html