面向对象编程

2020-05-16  本文已影响0人  LoveDuoer

实现原则

“面向对象编程”的关键点是“抽象”和“封装”,而“继承”、“多态”并不是核心,只能算是附加品。所以,我建议你在设计类的时候尽量少用继承和虚函数。如果非要用继承不可,那么我觉得一定要控制继承的层次,用 UML 画个类体系的示意图来辅助检查。如果继承深度超过三层,就说明有点“过度设计”了,需要考虑用组合关系替代继承关系,或者改用模板和泛型。

在设计类接口的时候,我们也要让类尽量简单、“短小精悍”,只负责单一的功能。如果很多功能混在了一起,出现了“万能类”“意大利面条类”(有时候也叫 God Class),就要应用设计模式、重构等知识,把大类拆分成多个各负其责的小类。

常用技巧

  1. 构造函数委托代理
    即存在多个参数不同的构造函数时,如果之间有通用的部分,可直接调用其他构造函数。例如:
class DemoDelegating final{
private: 
      int a; // 成员变量
public: 
      DemoDelegating(int x) : a(x) // 基本的构造函数
      {} 
      DemoDelegating() : // 无参数的构造函数 
            DemoDelegating(0) // 给出默认值,委托给第一个构造函数 
      {} 
      DemoDelegating(const string& s) : // 字符串参数构造函数 
            DemoDelegating(stoi(s)) // 转换成整数,再委托给第一个构造函数 
      {} 
};
  1. 成员变量初始化
    如果你的类有很多成员变量,那么在写构造函数的时候就比较麻烦,必须写出一长串的名字来逐个初始化,不仅麻烦还容易遗漏。在 C++11 里,你可以在类里声明变量的同时给它赋值,实现初始化,这样不但简单清晰,也消除了隐患。
class DemoInit final // 有很多成员变量的类{
private: 
      int a = 0; // 整数成员,赋值初始化 
      string s = "hello"; // 字符串成员,赋值初始化 
      vector v{1, 2, 3}; // 容器成员,使用花括号的初始化列表
public: 
      DemoInit() = default; // 默认构造函数 
      ~DemoInit() = default; // 默认析构函数
      DemoInit(int x) : a(x) 
      {} // 可以单独初始化成员,其他用默认值
};
  1. 类型别名
    C++11 扩展了关键字 using 的用法,增加了 typedef 的能力,可以定义类型别名。它的格式与 typedef 正好相反,别名在左边,原名在右边,是标准的赋值形式,所以易写易读。
using uint_t = unsigned int; // using别名
typedef unsigned int uint_t; // 等价的typedef
上一篇 下一篇

猜你喜欢

热点阅读