重构drawing时的一些想法
[TOC]
一、is-a 和 has-a
这两者远比看上去的要复杂。
首先明确一下两者的区别:
- 继承:is-a
- 关联:has-a
- 聚合:has-a(整体和部分可以分开,比如电脑和CPU、猫和动物)
- 组合:has-a(整体和部分不可以分开,比如公司和部门,没有公司,部门就不能存在)
举一个实际遇到的例子:
现在的 PlanManager 项目中,tpDetail(大样类) 和 tpLabel(文字标注类) 的关系就有异议:
丛工认为这两者应是继承于同一个基类的,因为他认为大样图也是标注的一种,应该和文字标注从同一个父类 tpBiaoZhu 中继承出来,然后把公共的成员变量提到 tpBiaoZhu 中,也就是文字和引线。这样就会导致 tpLabel 是空的,tpDetail中还是保持不动。
我、高工、常工则认为 tpDetail 和 tpLabel 不存在继承关系。因为大样图中是一定会有文字标注的,这二者是包含关系。这二者是各自一个单独的类,且 tpDetail 中会包含一个 tpLabel 的对象来表示大样图中的文字标注。
经过讨论最终丛工接受了我们的观点。(毕竟我们人多)
由上面的例子可以想到,其实两个类是否应该是继承关系,不能仅仅停留在个人理解上,而是要考虑类之间的包含关系和共同性是否足够。
二、类内
1. 类内函数
-
类内函数分类:
一个可以 实例化对象的类 ,类内函数要明确分为 如下两种:
- 成员函数:直接操作成员变量、成员变量的赋值和取值。
- static 纯方法:用来把一些通用的、与成员变量交互少的方法单独包出来。
-
函数声明:
任何类内的函数,均应合理使用 public、protected、private 声明:
private:新建一个函数时默认为 private,会被子类调用时改为 protected,会被外部调用时改为 public。protected:不会被外部调用,会被子类的成员函数调用的函数。public:会外部调用的函数。
-
参数:
入参 应加
const,出参用&修饰。给老函数新增参数的时候,应增加在最后且赋默认值,否则 难以保证兼容所有老的调用 。
-
函数修饰符:
使用以下修饰符,使代码可读性更高:
-
override:重写基类虚函数时,应在函数声明处添加,以区分 virtual 函数的重写或新增。 -
纯虚函数:当前类不会实例化对象,且要求子类必须实现此函数时,应将该函数声明为纯虚函数,例如:
1
virtual int Kind() = 0; // 子类的类型,用于区分各子类
-
2. 成员变量
成员变量不应是 public 类型的,默认应为 private ,有子类使用到时再改为 protected 。
成员变量存在的意义只应是存储信息。 每个成员变量应该是有具体含义的。
换句话说,以下类型是 不应 存在于成员变量中的:
- 类内各函数都会用到的公用参数,但是没有实际意义。例如
PlanManager中一些类中的m_Para指针,仅仅是为了取参数方便。 - 函数与函数之间的传参,也就是计算过程中的临时变量。
3. 一些特殊用途的类
有些类的用途就不是用来实例化对象的,例如:
- 纯虚类,用作接口供其他项目调用。
- 枚举类,用来存储一些固定的、有限的可选值。
- 工具类,用来存储一些通用的、与成员变量交互少的
static函数。 - 命令分发类,用来把命令分发给各个处理类。
- 单例类,用来存储一些全局的、唯一的对象。
三、关于裸指针
直接操作裸指针是一件非常危险的事情,但是 C++ 中又会不可避免的直接操作裸指针。
裸指针在使用时需要注意的地方:
-
避免成为野指针。
野指针:一个指向无效内存位置的指针
产生原因: 声明指针时未初始化。
delete后没有将该指针赋为nullptr,且后面又继续使用该指针。(这种情况下的指针也被特称为 悬空指针 ) -
储存在哪里,生命周期是多久?
-
临时变量。这种情况很容易导致内存泄漏,避免方法见上面的内容。
-
存在某个实例对象里。只要实例对象里能正确的管理好指针,就不会出问题。但前提是这个实例化的类可以正确的管理这个指针。
-
-
裸指针做临时变量时:
例如当使用裸指针做临时变量时,可以用一个
while(true)循包住数据处理的内容,有异常就从while中break出来,保证不管咋样都是能在最后delete指针的:
1
2
3
4
5
6
7
8
9
10
int nType = 9; // 定义数组大小
float* fDiaBar = new float[nType]; // new一个数组指针
while(true)
{
// 从pRCS中取数据:
pRCS->GetMainBar(fDiaBar, nType);
/*这里做一些其他数据处理,有异常就break*/
break; // 最后退出while
}
delete[] fDiaBar; // 最后delete数组指针
- 裸指针要交给某个类时:
-
裸指针最好时以成员变量的方式存在于某个类内,由类的析构函数负责
delete,由类内函数处理裸指针的赋值、拷贝和替换。 - 当一个指针从 new 出来,到交给 管理类 之前,期间的操作也应和上面的代码片段一样,把中间操作的内容放到一个
while(true)循环中,有异常就break出来,保证不管咋样都是能在最后指针交到 管理类 手里的。 - 或者是 new 出来就立刻交给 管理类 ,然后再针对这个指针该干啥干啥,这样即使有异常导致跳出,这个指针也有人负责了。
-