Verilog系列:new的初始化顺序
在SystemVerilog中,类可以认为是一种特殊且具有复杂数据结构的一种类型,其中包含数据成员和一些子程序成员(任务或者函数),数据成员主要用于存储与该类相关的状态信息,子程序一般负责执行赋予数据某些特定意义的操作.在类中,一般将这些数据成员称为类的属性,子程序称为类的方法,两者都是类成员.
类只有经过new()函数构造之后才能真正开辟对应的内存空间,创建对应的实例,才具有具体的意义.否则声明为该类的对象将指向null,不占用任何内存空间.构造函数是类中特殊的成员函数,只要创建class的实例都要执行构造函数,因此类对象具有可以动态创建的特点.构造函数主要作用就是保证每个对象的数据成员具有合适的初始状态,构造函数和其他的函数一样,可以没有形参也可以有多个形参,但是需要注意构造函数不能指定返回值,主要是因为其返回值是一个指向类本身的句柄.在具体使用时,一般可以显式的定义new的函数体也可以隐含的使用new(不声明不定义).
【示例】隐含的使用new函数
【仿真结果】
【示例】显式的使用带参数的new函数
【仿真结果】
该示例中,需要注意以下几点:
1、如果基类构造函数new()有参数,那么扩展类必须要有一个构造函数,并且在该构造函数中要执行super.new()调用父类构造函数;
2、cobj1、cobj0和cobj为继承关系,所以子类可以调用父类中的方法,实例化后的p可以调用其所有父类中的方法,但是不能以super.super.disp的方式调用(这里需要注意并不是所有方法或者数据都可以调用,详情参阅《Verilog系列:local和protected保护类成员》一文);
3、子类在实例化(p=new)时,其中的属性等并未实现初始化功能,而是先执行父类的初始化操作,即super.new()先于子类的初始化.示例中,super.new(d3)执行时因为子类的初始化并没有执行,所以此时的d3并没有初始值,传递给父类new的参数的值为对应被调用new函数参数变量类型的默认值0(此处为int型).当通过super.new(d3)执行到cobj0的new时,因为其是cobj的子类,所以会首先调用其构造函数new中的super.new(),即其父类的new函数.在cobj构造时,首先执行cobj中属性的初始化,此时b3被初始化为6,基类属性初始化完毕后,new中的代码将会被执行,此时b3在new中被a的值覆盖,即此时b3的值被修改为0.基类cobj中的new执行完毕后返回其子类cobj0.
4、返回子类cobj0首先会初始化cobj0中的属性,然后会执行其中new函数中super.new()之外的其他语句,所以此时虽然cobj0中的c3在属性初始化时初始化为1,但是c3在new中又被a覆盖,所以最终c3的值为a的默认值0.cobj0中的new执行完毕后返回其子类cobj1.
所以,上例的执行顺如源代码中的数字编号所示,基本流程如下图所示:
通过仿真结果可见,子类在构造时首先执行的是其new函数中的super.new(),即父类的构造函数,在父类的构造函数被调用时,首先会对父类的属性进行初始化,父类属性初始化完毕后,在执行父类中new函数中的相关语句,父类中的new函数执行完毕后返回子类,此时,首先进行的是子类中的属性初始化,然后再执行子类中new函数中除了super.new()以外的语句,从而完成子类的实例化.
因此,如果没有对类的属性进行合理的初始化操作,在对象实例化后得到的某些属性的初始值与期望不一致,所以建议不要在属性声明的同时进行初始化,具体的属性初始化操作均在new函数中进行.