virtual类型的函数在extern声明了之后,展开声明时还需要写virtual吗?
这是一个非常经典且容易产生困惑的 SystemVerilog 语法问题。
核心结论
在类体外(extern)展开声明时,不需要(也不建议)再写 virtual 关键字。
一旦你在类内部声明该函数为 virtual,这个属性就自动伴随该函数,无论是在类外定义还是在子类中重写,它永远都是虚函数。
1. 代码对比
正确写法:
cpp
class my_driver extends uvm_driver;
// 1. 类内声明:必须写 virtual
extern virtual function void build_phase(uvm_phase phase);
endclass
// 2. 类外展开:不要写 virtual
function void my_driver::build_phase(uvm_phase phase);
super.build_phase(phase);
// ... 逻辑内容
endfunction
错误(或冗余)写法:
如果在类外写成 virtual function void my_driver::build_phase...,编译器通常会报错,或者至少会给出一个警告。因为 virtual 是成员的属性修饰符 ,而类外定义只是内容的填充。
2. 为什么会有这种规定?
这主要源于底层语言的设计逻辑(类似于 C++):
-
属性在"户口本"上: 类内部的声明(Declaration)就像是函数的"户口本",它定义了函数的名称、参数、返回值以及属性(是否为 virtual、是否为 local 等)。
-
类外只是"施工现场": 类外的定义(Implementation)只是告诉编译器函数具体怎么执行。此时编译器已经通过类内的声明知道了它是
virtual,因此不需要重复。
3. 相关规则扩展
| 关键字 | 类内声明 (Inside) | 类外展开 (Outside) | 说明 |
|---|---|---|---|
| virtual | 必须写 | 不能写 | 虚函数属性在声明时确定。 |
| static | 必须写 | 不能写 | 静态成员函数的定义不带 static。 |
| local / protected | 必须写 | 不能写 | 访问权限仅由类内声明决定。 |
| default 参数 | 写在声明处 | 不能写 | 参数默认值(如 int a=5)只能出现在类内。 |
4. 总结
你只需要记住:关键字(virtual, static, local)只在"类体内部"这个地盘生效,一旦出了类的大门(extern 展开),这些修饰符统统脱掉。