SystemVerilog学习——类的继承

目录

一、概述

二、基本概念

三、继承的意义

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
  • 继承父类的成员:子类自动继承父类的成员变量和方法,除非子类重写了这些方法或成员。
  • 重写方法:子类可以重写父类的方法,通过 functiontask 重新定义同名方法。如果子类希望在重写方法中调用父类的实现,可以使用 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 是一个父类,DogCat 是它的子类。通过父类 Animal 的引用,我们可以动态地调用子类 DogCat 中的不同实现,这就是多态性。

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() 方法,CircleSquare 子类重写了该方法,分别实现了不同形状的绘制功能。通过这种方式,我们可以保持代码的组织性和可扩展性。

3.5 提升可维护性(Maintainability)

        通过继承,如果父类中的逻辑发生变化,所有继承自父类的子类都可以直接受益。我们只需要修改父类中的代码,而不需要逐一修改所有子类中的代码。这极大地提高了系统的可维护性和可扩展性。

        如果父类中的 speak() 方法发生变化,所有继承自 Animal 的类都会自动更新,无需手动修改每一个子类。

四、访问控制

        在继承中,父类的成员变量和方法的访问控制(如 publicprotectedprivate)会影响子类的访问权限。

  • 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 中创建层次化的类结构,这对于大型验证环境和复用组件非常有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

apple_ttt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值