学习记录10(类的封装)
1.封装
封装是面向对象编程的核心思想,是指将对象的属性和行为封装起来,封装的载体是类,类通常对用户隐藏其实现的细节,这就是封装的思想。
采用封装的思想保证了类内部数据结构的完整性,应用该类的用户不能轻易直接操纵该数据结构,而只能执行该类允许公开的数据。这样可以避免外部对内部数据的影响,提高程序的可维护性。
2.类与结构体的异同
二者都是容器,都可以定义数据成员;
• 类变量在声明之后,需要构造(construction)才会构建对象(object)实体,而struct在变量声明时已经开辟内存。
• 类除了可以声明数据变量成员,还可以声明方法(function/task),而struct则不能。
• 从根本来讲,结构体是用户根据实际需要定义的复合数据类型,而class是对某一类事物的抽象模板,类中不仅有数据类型属性成员,还包括对这些属性成员操作的一系列方法。
前面也让有这方面的。详见:https://www.cnblogs.com/tuck0603/p/21445841
3.类与模块的异同
• 从数据和方法上说,两者均可以作为封闭的容器来定义和存储。
• 从硬件和软件的角度看,硬件在实现必须通过module实现,module在仿真开始时就确定是否能被例化以及变量(动态/静态),类的部分可以在仿真任何阶段声明并动态创建出新的对象,这正是软件操作更为灵活的地方。
•从封装性(encapsulation)来看,模块内的变量和方法是对外部公共(public)开放的,而类则可以根据需要来确定外部访问的权限是否是默认的公共类型、或者受保护类型(protected)还是私有类型(local)。
• 从继承性(inheritance)来看,模块没有继承性,即无法在原有module的基础上进行新module功能的扩展,如果需要前设计的module功能则必须通过拷贝旧的module然后进行修改从而生成一个新的module的方式。而继承性是类的一大特点,不用拷贝也能使用父类所定义的方法和属性。
类的继承包括了继承父类的成员变量和成员方法。也就说一个子类在继承父类成员变量的同时也继承了父类操作这些成员变量的成员方法。这是前面这个链接:https://www.cnblogs.com/tuck0603/p/21445841
子类在定义new函数时,需要先调用父类的new函数即super.new()。如果父类的new函数没有参数,子类也可以省略该调用,而系统会在编译时自动添加super.new()。
解释
为什么要子类定义内存时需要先调用父类的new函数呢?
当你执行子类B(B b_obj = new();) 时,仿真器在堆中分配的内存块不是一个整体,而是由两块拼接而成的:
第一块(父类部分):存放类 A 中定义的所有变量(a_val, b_val 等)。
第二块(子类部分):存放类 B 中新增的变量(c_val 等)。
问题来了:子类部分的初始化代码(比如 this.c_val = 0;)只认识自己的内存区域。如果父类部分的变量没有被初始化(即没有执行 super.new()),它们就会处于完全未定义的状态(垃圾值)。因此,必须先执行 super.new(),把父类部分的“地基”打好,子类才能安全地“往上盖楼”,**也就是说子类是依托于父类内存的,如果父类没有声明内存空间,那么子类可以直接通过new()创建自己的内存空间。**
对象创建时的初始化顺序:
• 子类的实例对象在初始化时首先会调用父类的构造函数。(构造函数只是一个普通函数,这里指的是new(),它的唯一职责是:给当前对象的内存空间填初值)
• 当父类构造函数完成时,会将子类实例对象中各个成员变量按照它们定义时显式的默认值初始化,如果没有默认值则不被初始化。
• 在成员变量默认值初始化后(声明的同时即赋值),才会最后进入用户定义的new函数中执行剩余的初始化代码。