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

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

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

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

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 virtual becomes 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 virtual method 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
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5