目录
一、概述
二、基本概念
三、继承的意义
3.1 代码复用(Code Reusability)
3.2 扩展功能(Functionality Extension)
3.3 多态性(Polymorphism)
3.4 简化代码结构(Code Organization)
3.5 提升可维护性(Maintainability)
四、访问控制
五、父类方法的重载和覆盖
六、总结
一、概述
在 SystemVerilog (SV) 中,类的继承机制与面向对象编程(OOP)中的继承概念类似,允许我们基于现有的类创建新类,以便重用代码和扩展功能。通过继承,子类可以继承父类的属性(成员变量)和方法(成员函数),并且可以覆盖父类的方法,也可以新增自己的属性和方法。继承有助于实现代码的重用、扩展和多态性。
二、基本概念
        在 SystemVerilog 中,继承通过在类定义时使用 extends 关键字来实现。子类会继承父类的所有公共和保护成员,并可以重写父类的方法,也可以添加自己的成员。
class ParentClass;
    // 父类成员变量
    int x;
    
    // 父类构造函数
    function new();
        x = 0;
    endfunction
    
    // 父类方法
    function void display();
        $display("x = %0d", x);
    endfunction
endclass
class ChildClass extends ParentClass;  // 继承父类
    // 子类成员变量
    int y;
    
    // 子类构造函数
    function new();
        super.new();  // 调用父类构造函数
        y = 0;
    endfunction
    
    // 子类重写父类的方法
    function void display();
        super.display();  // 调用父类的方法
        $display("y = %0d", y);
    endfunction
endclass
- 继承父类的成员:子类自动继承父类的成员变量和方法,除非子类重写了这些方法或成员。
- 重写方法:子类可以重写父类的方法,通过
function或task重新定义同名方法。如果子类希望在重写方法中调用父类的实现,可以使用super关键字来调用父类的同名方法。- 构造函数:子类可以定义自己的构造函数,如果子类构造函数中需要调用父类构造函数,必须使用
super.new()显式调用父类的构造函数。- 成员变量的继承:子类会继承父类的成员变量,但是子类可以根据需要新增或修改成员变量。父类的成员变量在子类中保持可访问(除非是私有的)。
- 多态性:通过继承,子类可以实现不同的行为来覆盖父类的行为,这对于在仿真中实现不同类型的对象非常有用。
使用示例:
module test;
    initial begin
        // 创建父类和子类对象
        ParentClass p = new();
        ChildClass c = new();
        // 使用父类对象调用方法
        p.display();   // 输出 "x = 0"
        
        // 使用子类对象调用方法
        c.display();   // 输出 "x = 0" 和 "y = 0"
    end
endmodule
三、继承的意义
继承是面向对象编程(OOP)中的一个核心概念,它在 SystemVerilog 中也有着重要的作用。继承允许我们通过从已有的类(父类)创建新的类(子类)来实现代码的复用和扩展,避免重复的代码,提高代码的可维护性和可扩展性。继承带来的好处主要有以下几个方面:
3.1 代码复用(Code Reusability)
继承最直接的作用是实现代码的复用。子类可以继承父类的成员变量和方法,从而无需重复编写相同的代码。例如,如果你有一个基础类(父类),可以通过继承将其功能扩展到其他类(子类)中,而不需要重新实现父类已经完成的部分。
class Animal;
    string name;
    function new(string name);
        this.name = name;
    endfunction
    function void speak();
        $display("Animal sound");
    endfunction
endclass
class Dog extends Animal;
    function new(string name);
        super.new(name);  // 调用父类构造函数
    endfunction
    function void speak();
        $display("%s says Woof!", name);
    endfunction
endclass
        在这个例子中,Dog 类继承了 Animal 类的 name 成员变量和 speak() 方法,并且通过重写 speak() 方法,定义了 Dog 特有的行为。 
3.2 扩展功能(Functionality Extension)
继承不仅仅是复用父类的代码,它还允许子类在继承的基础上扩展新的功能。子类可以通过新增自己的成员变量或方法来扩展父类的功能。这样,子类就可以在父类功能的基础上增加新的行为或特性。
class Car;
    string model;
    function new(string model);
        this.model = model;
    endfunction
    function void drive();
        $display("%s is driving", model);
    endfunction
endclass
class ElectricCar extends Car;
    string battery_type;
    function new(string model, string battery_type);
        super.new(model);  // 调用父类构造函数
        this.battery_type = battery_type;
    endfunction
    function void charge();
        $display("%s is charging", battery_type);
    endfunction
endclass
         在这个例子中,ElectricCar 类继承了 Car 类,并且新增了一个 battery_type 成员变量和一个 charge() 方法,使得电动汽车除了具备普通汽车的功能外,还可以充电。
3.3 多态性(Polymorphism)
继承支持多态性(Polymorphism),即通过父类指针或引用来调用不同子类的实现。多态性是面向对象编程中的一种机制,它允许通过统一的接口调用不同的实现方式,极大地提高了系统的灵活性和可扩展性。
class Animal;
    function void speak();
        $display("Animal sound");
    endfunction
endclass
class Dog extends Animal;
    function void speak();
        $display("Woof!");
    endfunction
endclass
class Cat extends Animal;
    function void speak();
        $display("Meow!");
    endfunction
endclass
module test;
    initial begin
        Animal a;
        Dog d;
        Cat c;
        a = new();
        d = new();
        c = new();
        a.speak();  // 输出 "Animal sound"
        d.speak();  // 输出 "Woof!"
        c.speak();  // 输出 "Meow!"
    end
endmodule
         在这个例子中,Animal 是一个父类,Dog 和 Cat 是它的子类。通过父类 Animal 的引用,我们可以动态地调用子类 Dog 和 Cat 中的不同实现,这就是多态性。
3.4 简化代码结构(Code Organization)
继承能够帮助我们组织代码,使得代码结构更清晰。子类通过继承父类,可以专注于实现差异化的功能,而共享和通用的功能则由父类来提供。这样可以减少重复代码,使得系统的设计更加简洁和模块化。
class Shape;
    function void draw();
        $display("Drawing shape");
    endfunction
endclass
class Circle extends Shape;
    function void draw();
        $display("Drawing circle");
    endfunction
endclass
class Square extends Shape;
    function void draw();
        $display("Drawing square");
    endfunction
endclass
        在这个例子中,Shape 是父类,它提供了一个通用的 draw() 方法,Circle 和 Square 子类重写了该方法,分别实现了不同形状的绘制功能。通过这种方式,我们可以保持代码的组织性和可扩展性。
3.5 提升可维护性(Maintainability)
通过继承,如果父类中的逻辑发生变化,所有继承自父类的子类都可以直接受益。我们只需要修改父类中的代码,而不需要逐一修改所有子类中的代码。这极大地提高了系统的可维护性和可扩展性。
        如果父类中的 speak() 方法发生变化,所有继承自 Animal 的类都会自动更新,无需手动修改每一个子类。
四、访问控制
        在继承中,父类的成员变量和方法的访问控制(如 public、protected 和 private)会影响子类的访问权限。
- public:子类可以直接访问父类的公共成员。
- protected:子类可以访问父类的受保护成员,但无法在类外部访问。
- private:子类不能访问父类的私有成员,尽管它们可以在类内部定义和使用自己的私有成员
五、父类方法的重载和覆盖
        子类可以重载父类的方法,也可以覆盖父类的方法。如果子类方法需要调用父类的版本,可以使用 super 关键字:
class Parent;
    function void foo();
        $display("Parent foo");
    endfunction
endclass
class Child extends Parent;
    // 重写父类方法
    function void foo();
        $display("Child foo");
        super.foo();  // 调用父类的 foo 方法
    endfunction
endclass
六、总结
- 继承使得子类可以扩展和重用父类的功能。
- 多态性允许子类定义自己的行为,而不必修改父类代码。
super关键字用于调用父类的方法和构造函数。- 类的成员访问控制决定了哪些成员可以被继承和访问。
通过继承,我们可以在 SystemVerilog 中创建层次化的类结构,这对于大型验证环境和复用组件非常有帮助。



















