1. 父类的句柄指向子类的对象
对于子类来讲,通过复制操作,是可以直接赋值给父类,也就是说,父类的句柄可以直接指向子类。但是反过来操作,是不可以的,并且在指向的过程中,父类的句柄仍然无法访问子类的属性,父类和子类之间的赋值操作如下图所示代码块。
1. program cls_cp;
2. class base_cls;
3. int a = 100;
4. inner_cls i_a;
5. function new();
6. i_a = new();
7. endfunction
8. endclass
9.
10. class child_cls extends base_cls;
11. int b = 300;
12. endclass
13.
14. initial begin
15. base_cls base_0;
16. child_cls child_0;
17. child_0 = new();
18. base_0 = child_0;
19. end
20.
21. endprogram
这种赋值操作,父类无需使用new函数,因为子类已经new过,分配好地址空间,赋值是将句柄赋值,因此父类的空间已经分配好,且父类和子类的对象是共享存储空间的。如下图所示:
仿一下看看:
改变一个,另一个跟着改变。再试试改变父类的属性。
可以注意到一个细节,虽然父类的句柄指向了子类,但是父类的句柄其实是指向了子类继承的父类所在内存空间,父类仍然是无法访问子类的属性的。
直接报错,说在父类中找不到对象b,因此父类的句柄只是指向了子类的父类所划的空间。如果父类增加new操作呢?也是可以的,只是过程变为如下图所示:
2 子类的句柄指向父类的对象
子类句柄赋值给父类的句柄操作,是可以的,那么反过来操作是否可以?答案是不行的,因为父类的句柄,并不包含子类的对象的属性,因此直接父类句柄直接赋值给子类的句柄,会造成访问错误,因为编译器认为,子类比父类包含更加丰富的信息,而父类的句柄类型决定了其不包含有子类的属性,这也是类的继承的特点,只有子类可以访问父类的成员变量,代码块如下:
1. program cls_cp;
2. class base_cls;
3. int a = 100;
4. inner_cls i_a;
5. function new();
6. i_a = new();
7. endfunction
8. endclass
9.
10. class child_cls extends base_cls;
11. int b = 300;
12. endclass
13.
14. initial begin
15. base_cls base_0;
16. child_cls child_0;
17. base_0 = new();
18. child_0 = base_0;
19. end
20.
21. endprogram
仿一下看看:
可以看到直接报错了。
3 使用new函数的复制
父类与子类之间的复制操作,同样可以通过new函数实现浅拷贝,值得注意的是,复制规则也只能由子类的句柄复制给父类,也就是父类的句柄只能指向子类的对象,反过来是不行的,实现规则同样为浅拷贝。代码如下:
1. program cls_cp;
2. class base_cls;
3. int a = 100;
4. inner_cls i_a;
5. function new();
6. i_a = new();
7. endfunction
8. endclass
9.
10. class child_cls extends base_cls;
11. int b = 300;
12. endclass
13.
14. initial begin
15. base_cls base_0;
16. child_cls child_0;
17. child_0 = new();
18. base_0 = new child_0;
19. end
20.
21. endprogram
仿一下看看:
这个实现的其实就是浅拷贝过程,如下图所示:
浅拷贝内置类指向同一块地址空间。改变父类的顶层类,不会影响子类,但是改变深层类,会影响子类。
反过来复制呢?会直接报错:
4 类的多态特性
多态赋予了类更多的变化和可能性,类变量中用virtual修饰的函数或任务,在子类中可以进行改写,改写过后,通过子类赋值给父类的这种操作,父类再调用virtual修饰的函数时,其实是调用的子类的函数。仿一下:
如果父类的函数没有被virtual修饰,子类没办法对父类的函数改写,因此也失去了多态的特性。