SystemVerilog prohibits a class declared as virtual from being directly instantiated — this is called an abstract class. However, an abstract class can still be extended to form other sub-classes, which can then be instantiated normally. This is useful for enforcing that testcase developers always extend a base class to form another class for their needs — so base classes are commonly declared virtual, though it isn't mandatory.
11 min read | Intermediate Level
What You'll Learn
- What makes a class "abstract" in SystemVerilog, and why it can't be instantiated directly
- How an abstract class can still be extended into usable subclasses
- What a pure virtual method is, and why its implementation is mandatory in every subclass
- Why abstract base classes are a common pattern for enforcing a required interface
Syntax
virtual class
// class definition
endclass
A Normal Class
For comparison, here's an ordinary class, instantiated normally:
class BaseClass;
int data;
function new();
data = 32'hc0de_c0de;
endfunction
endclass
module tb;
BaseClass base;
initial begin
base = new();
$display ("data=0x%0h", base.data);
end
endmodule
Output
ncsim> run data=0xc0dec0de ncsim: *W,RNQUIE: Simulation is complete.
Making It Abstract With virtual
Declaring the exact same class virtual turns it into an abstract class:
virtual class BaseClass;
int data;
function new();
data = 32'hc0de_c0de;
endfunction
endclass
module tb;
BaseClass base;
initial begin
base = new();
$display ("data=0x%0h", base.data);
end
endmodule
Output
base = new(); | ncvlog: *E,CNIABC (testbench.sv,12|5): An abstract (virtual) class cannot be instantiated.
The exact same code that worked a moment ago now fails to compile, purely because of the added virtual keyword on the class declaration.
Quick Check
Q: Would using a typed constructor, like BaseClass base = BaseClass::new;, avoid this error?
Show Answer
No. The restriction is on the class itself — it's abstract, so no syntax for directly constructing a BaseClass object will work. The only way around it is to extend the class and instantiate the subclass instead.
Extending an Abstract Class
Abstract classes can be extended just like any other SystemVerilog class, using extends:
virtual class BaseClass;
int data;
function new();
data = 32'hc0de_c0de;
endfunction
endclass
class ChildClass extends BaseClass;
function new();
data = 32'hfade_fade;
endfunction
endclass
module tb;
ChildClass child;
initial begin
child = new();
$display ("data=0x%0h", child.data);
end
endmodule
Output
ncsim> run data=0xfadefade ncsim: *W,RNQUIE: Simulation is complete.
ChildClass's constructor never writes super.new() explicitly, but since BaseClass's constructor takes no required arguments, SystemVerilog still calls it implicitly first — briefly setting data to 0xc0dec0de — before ChildClass's own constructor body runs and immediately overwrites it to 0xfadefade. See SystemVerilog Class Constructor for more on this implicit-call behavior.
Quick Check
Q: If ChildClass's constructor body were completely empty, what would child.data show?
Show Answer
0xc0dec0de. With no explicit body to overwrite it, the implicitly-called base constructor's assignment would be the only thing setting data, and it would simply remain at that value.
Pure Virtual Methods
A virtual method inside an abstract class can be declared with the keyword pure, making it a pure virtual method. Such a method only specifies a prototype within the abstract class — no body at all — and its actual implementation is left entirely to the subclasses that extend it.
Pure Method Example
virtual class BaseClass;
int data;
pure virtual function int getData();
endclass
class ChildClass extends BaseClass;
virtual function int getData();
data = 32'hcafe_cafe;
return data;
endfunction
endclass
module tb;
ChildClass child;
initial begin
child = new();
$display ("data = 0x%0h", child.getData());
end
endmodule
The pure virtual method's prototype and its implementation must share the same arguments and return type.
Output
ncsim> run data = 0xcafecafe ncsim: *W,RNQUIE: Simulation is complete.
Notice BaseClass's getData() declaration ends right at the semicolon — no endfunction, no body at all. All of the actual logic lives entirely inside ChildClass's own implementation.
Quick Check
Q: If ChildClass didn't implement getData() at all, could child = new(); still succeed?
Show Answer
No. A class that inherits a pure virtual method without providing its own implementation remains abstract itself — the same restriction that blocks instantiating BaseClass directly would apply to ChildClass too, until every inherited pure virtual method has a concrete implementation somewhere in the chain.
Where Are Abstract Classes Used?
Abstract base classes with pure virtual methods are a common way to guarantee a required interface across every component in a verification environment — forcing every user-written driver, monitor, or scoreboard extension to provide a specific method, catching a missing implementation as a compile-time error instead of a confusing gap discovered only at run time.
Common Beginner Mistakes
Mistake #1: Trying to directly instantiate an abstract class
As the second example shows, this is always a compile-time error, regardless of what syntax is used to attempt it. Why? An abstract class exists specifically to be extended, not instantiated on its own — the whole point is to force every actual object to come from a more specific subclass.
Mistake #2: Forgetting that extending an abstract class still runs its constructor
Even without writing super.new() explicitly, the base class's own constructor logic still runs first, as the "Extending an Abstract Class" example shows. Why? This can be surprising if the base constructor has a side effect (like the counters covered in earlier articles) that the child class doesn't expect to happen automatically.
Mistake #3: Trying to give a pure virtual method a body
A pure virtual method's declaration in the abstract class ends at the semicolon — adding a body there is a compile-time error. Why? The entire point of pure is that the implementation is mandatory in a subclass, not optional in the base class — providing a body in the base would defeat that requirement.
Mistake #4: Leaving a pure virtual method unimplemented in a subclass
As the third Quick Check shows, this leaves the subclass abstract too, blocking its own instantiation. Why? Every pure virtual method inherited from a base class needs a real implementation somewhere in the chain before any concrete object can actually be constructed.
Practice Exercise
Challenge: Two Pure Virtual Methods
Extend BaseClass with a second pure virtual method, getDoubled(), that should return data multiplied by 2. Implement both methods in ChildClass, and predict the output of calling each.
Hint
Both methods need their own prototype-only declaration in the abstract base class, and both need a full implementation in the child class — leaving either one unimplemented would keep ChildClass abstract too.
Solution
virtual class BaseClass;
int data;
pure virtual function int getData();
pure virtual function int getDoubled();
endclass
class ChildClass extends BaseClass;
virtual function int getData();
data = 32'hcafe_cafe;
return data;
endfunction
virtual function int getDoubled();
return data * 2;
endfunction
endclass
module tb;
ChildClass child;
initial begin
child = new();
$display ("data = 0x%0h", child.getData());
$display ("doubled = 0x%0h", child.getDoubled());
end
endmodule
The first call sets and returns 0xcafecafe, exactly as before. The second call reads the now-set data and returns 0x95fd95fc — double 0xcafecafe, wrapped within the 32-bit width of int — confirming both pure virtual methods needed independent implementations before ChildClass could be instantiated at all.
Summary
In this tutorial, you learned:
- A class declared
virtualbecomes abstract, and cannot be directly instantiated — only extended - Extending an abstract class still runs its constructor logic, even without an explicit
super.new()call, as long as the base constructor requires no arguments - A
pure virtualmethod has only a prototype in the abstract class, with no body — the implementation is mandatory in a subclass - A subclass that doesn't implement every inherited pure virtual method remains abstract itself, and can't be instantiated either
- Abstract classes with pure virtual methods are a common way to enforce a required interface across every component that extends them