SystemVerilog中super.func()调用时内部类指针为空的问题
SystemVerilog多层继承中super.func()调用时inner类指针为空的问题分析与解决
复现代码
// 内层配置类 class inner_A; int val_a; function new(); val_a = 10; endfunction virtual function void print(); $display("inner_A val_a: %0d, this ptr: %p", val_a, this); endfunction endclass class inner_B extends inner_A; int val_b; function new(); val_b = 20; endfunction virtual function void print(); super.print(); $display("inner_B val_b: %0d, this ptr: %p", val_b, this); endfunction endclass class inner_C extends inner_B; int val_c; function new(); val_c = 30; endfunction virtual function void print(); super.print(); $display("inner_C val_c: %0d, this ptr: %p", val_c, this); endfunction endclass // 主继承类 class class_A; inner_A cfg; function new(); cfg = new(); endfunction virtual function void print(); $display("class_A cfg ptr: %p", cfg); cfg.print(); endfunction endclass class class_B extends class_A; inner_B cfg; function new(); cfg = new(); endfunction virtual function void print(); super.print(); $display("class_B cfg ptr: %p", cfg); cfg.print(); endfunction endclass class class_C extends class_B; inner_C cfg; function new(); cfg = new(); endfunction virtual function void print(); super.print(); $display("class_C cfg ptr: %p", cfg); cfg.print(); endfunction endclass module top; initial begin class_C c = new(); c.print(); end endmodule
问题原因
- 变量遮蔽(Shadowing):class_B和class_C中重新声明了
cfg变量,遮蔽了父类class_A、class_B的同名变量。当调用super.print()时,父类的print()函数只能访问自身层级的cfg,而非子类的cfg。 - 未初始化父类变量:子类构造函数仅初始化了自身层级的
cfg,父类的cfg变量未被初始化,导致父类print()执行时指针为空。
解决方法
方法1:统一基类变量,利用多态(推荐)
将cfg变量仅在基类class_A中声明,子类通过构造函数传入不同类型的inner对象,借助多态实现层级访问:
// 修改后的主继承类 class class_A; inner_A cfg; function new(inner_A cfg_inst); cfg = cfg_inst; endfunction virtual function void print(); $display("class_A cfg ptr: %p", cfg); cfg.print(); endfunction endclass class class_B extends class_A; function new(inner_B cfg_inst); super.new(cfg_inst); endfunction virtual function void print(); super.print(); $display("class_B cfg ptr: %p", cfg); // 通过类型转换访问inner_B专属成员 $display("inner_B val_b: %0d", inner_B'(cfg).val_b); endfunction endclass class class_C extends class_B; function new(inner_C cfg_inst); super.new(cfg_inst); endfunction virtual function void print(); super.print(); $display("class_C cfg ptr: %p", cfg); $display("inner_C val_c: %0d", inner_C'(cfg).val_c); endfunction endclass module top; initial begin inner_C inner_c = new(); class_C c = new(inner_c); c.print(); end endmodule
方法2:显式初始化父类变量
若需保留子类的同名cfg变量,需在子类构造函数中显式初始化所有父类层级的cfg:
class class_B extends class_A; inner_B cfg; function new(); super.new(); // 初始化class_A的cfg cfg = new(); super.cfg = cfg; // 将父类cfg指向当前子类的cfg endfunction virtual function void print(); super.print(); $display("class_B cfg ptr: %p", cfg); cfg.print(); endfunction endclass class class_C extends class_B; inner_C cfg; function new(); super.new(); // 初始化class_B和class_A的cfg cfg = new(); super.cfg = cfg; class_A::cfg = cfg; // 显式指定初始化顶层父类的cfg endfunction virtual function void print(); super.print(); $display("class_C cfg ptr: %p", cfg); cfg.print(); endfunction endclass
方法3:临时调试用的向下转型(不推荐)
在父类方法中通过向下转型强制访问子类的cfg,但此方式破坏封装性,仅适合临时调试:
class class_A; inner_A cfg; virtual function void print(); class_C c_cast; if ($cast(c_cast, this)) begin cfg = c_cast.cfg; $display("class_A cfg ptr: %p", cfg); cfg.print(); end endfunction endclass
内容的提问来源于stack exchange,提问作者Андрей Ефимов
相关产品推荐
相关产品推荐

