面向对象 —— 类设计(一)
面向对象 —— 类设计(二)
面向对象 —— 类设计(三)
面向对象 —— 类设计(五)
- 普通成员变量,也即普通属性,属于类的各个实例化对象。那么该如何判断类的成员方法是不是静态的呢?
- 就看它是否需要访问类的非静态成员(在其方法内部会否用到类的普通成员变量/方法);
- 如果没用到类的普通成员变量/方法,也就是不需要该变量或方法,也就是不依赖于类的实例化对象;
1. “静态成员函数”是如何炼成的?
静态成员函数:不通过对象(类的实例化)即可调用的成员方法;
该类为功能类(用于操作、处理或者计算),则这些静态成员函数一般为公有(public)
尤其对于纯面向对象的语言,比如 Java,功能类及其公有静态成员函数的设计不可避免,在C++(多范式编程语言)中,功能类及其公有静态成员函数可被全局函数所取代;
该类为持有数据的类。
情况会有些复杂,但有一点可以明确的是,该类的静态成员函数不会也不能调用当前类的非静态成员变量/成员函数,也即该成员函数欲成为静态成员函数的先决条件(或称必要条件),是该方法与类的非静态数据及方法没有任何关联。即如果一个类的某一成员函数不依赖于其内部的非静态成员、非静态的成员函数(所有未被static修饰的成员),就可以将该类设计为静态的成员函数。试想,我们所遇到的大部分的类的成员函数,如果不为static的话,其是否需要跟非静态的数据成员发生交互,是否会调用该类内部的其他非静态的成员函数。
所有的非静态成员变量及成员方法是(仅)服务于对象的;
类静态成员(变量及方法)不依对象的存在而存在,也即无需创建对象直接通过类名即可访问或者调用静态成员。试想如果在静态成员函数的内部调用非静态成员或函数(而这些非静态成员依赖对象的创建),显然逻辑上是有问题的。
2. 持有基类的指针——多态的实现
当我们需要调用所有继承自该基类的子类的成员时,只需使用dynamic_cast
进行向下(沿着继承关系,向下,也即子类的方向)类型转换。
形参中的基类指针,更像只是一个声明,当然并未真正初始化,客户端调用时将真正的值(往往是子类指针,因为基类向下纵向的继承关系,并非只有一层,横向兄弟关系的子类中也可以有多个,也即实现了统一的交由基类指针调用,具体的执行在每一个基类)赋给它用以初始化。
多态,只在接口(全局函数、类的成员函数)中给出基类指针的形参。首先只维护一个基类指针(并非初始化),调用时,可将该基类指针指向任一派生类对象,实现多态(父类指针指向父类对象,是不构成多态的,也是无法真正向下类型转换的,纵然通过static_cast/dynamic_cast进行向下类型转换,使用static_cast将会导致转换后的子类指针调用子类的成员时的未定义行为,使用dynamic_cast转换后的子类指针为nullptr,因为其执行的是运行时的检查)。
3. 再说静态成员变量
当在类外对静态成员变量进行定义时,为什么不需要加static
关键字。
能在类外定义的成员变量一定是静态变量,再加的话,其实是一种冗余性说明。