《The UVM Primer》chapter6: Polymorphism

多态这个词源于面向对象的类是从其他类里继承。一个正方形就是一个长方形,一个平行四边形,一个梯形,一个多边形。这就让人要发问了:"我声明了一个多边形类型的变量, 然后例化了一个正方形对象,那我可以用这个多边形变量来存放正方形对象吗?" 答案是肯定的,这种语言特性叫做多态。

我们有一个 animal 基类和两个基类的继承类 lion 和 chicken。所有的动物类都有一个数据成员 age 和一个方法 make_sound( )。这个方法将动物的叫声打印到屏幕上。

lion 从 animal 里继承得到了 age 数据成员。new( )方法将 age 传递到 animal 的构造函数,这里重载了 make_sound( )函数来弄出狮子的叫声。

chicken 类也做了同样的事情,只是叫声不一样了。两个类中的 new( )方法都调用了父类构造函数并传入 age。这个代码有一个问题: "如果我只是调用 super.new( )构造函数的话,为什么不能直接从基类里面继承这个构造函数呢?" 答案是我们的构造函数是有参数的,SystemVerilog 要求我们显式的写出带参数的构造参数,即使我们只是调用了父类构造函数。

用 animal_h 变量来存放 lion 和 chicken 对象,这是合法的,因为 lion 和

chicken 是从 animal 派生的。

class animal;
   int age=-1;

   functionnew(int a);
      age = a;
   endfunction : new

   functionvoid make_sound();
      $fatal(1, "Generic animals don't have a sound.");
   endfunction : make_sound

endclass : animal


class lion extends animal;

   functionnew(int age);
      super.new(age);
   endfunction : new

   functionvoid make_sound();
      $display ("The Lion says Roar");
   endfunction : make_sound

endclass : lion


class chicken extends animal;

   functionnew(int age);
      super.new(age);
   endfunction : new

   functionvoid make_sound();
      $display ("The Chicken says BECAWW");
   endfunction : make_sound

endclass : chicken


module top;


   initialbegin
   
      lion   lion_h;
      chicken  chicken_h;
      animal animal_h;
      
      lion_h  = new(15);
      lion_h.make_sound();
      $display("The Lion is %0d years old", lion_h.age);
      
      chicken_h = new(1);
      chicken_h.make_sound();
      $display("The Chicken is %0d years old", chicken_h.age);

      animal_h = lion_h;
      animal_h.make_sound();
      $display("The animal is %0d years old", animal_h.age);
      
      animal_h = chicken_h;
      animal_h.make_sound();
      $display("The animal is %0d years old", animal_h.age);
      
   end// initial begin

endmodule : top

虚函数

SystemVerilog 在很多地方都用了 virtual 关键字,用"virtual"定义的东西其实是一个之后才会实现的占位符,或是在其他地方才有效的。当你把一个方法定义为虚方法时,这是在指示 SystemVerilog 忽略变量类型的表面限制,去更

深入的查看存放在变量里的对象的类型,你就可以找出真正的方法了。

和原先的代码不同是关键词virtual,lion和chicken里的make_sound( )定义是不需要virtual关键字的,因为它们从基类中继承了这个行为。随后,我们使用animal_h.make_sound( )的调用根据变量存放的对象类型返回了不同的结果。

class animal;
   int age=-1;

   functionnew(int a);
      age = a;
   endfunction : new

   virtualfunctionvoid make_sound();
      $fatal(1, "Generic animals don't have a sound.");
   endfunction : make_sound

endclass : animal


class lion extends animal;

   functionnew(int age);
      super.new(age);
   endfunction : new

   functionvoid make_sound();
      $display ("The Lion says Roar");
   endfunction : make_sound

endclass : lion


class chicken extends animal;

   functionnew(int age);
      super.new(age);
   endfunction : new

   functionvoid make_sound();
      $display ("The Chicken says BECAWW");
   endfunction : make_sound

endclass : chicken


module top;


   initialbegin
   
      lion   lion_h;
      chicken  chicken_h;
      animal animal_h;
      
      lion_h  = new(15);
      lion_h.make_sound();
      $display("The Lion is %0d years old", lion_h.age);
      
      chicken_h = new(1);
      chicken_h.make_sound();
      $display("The Chicken is %0d years old", chicken_h.age);

      animal_h = lion_h;
      animal_h.make_sound();
      $display("The animal is %0d years old", animal_h.age);
      
      animal_h = chicken_h;
      animal_h.make_sound();
      $display("The animal is %0d years old", animal_h.age);
      
   end// initial begin

endmodule : top

抽象类和纯虚函数

我们之前版本的动物类,为了解决一个简单的问题使用了一个厚重的方案。我们希望强制用户去重载make_sound()方法,于是我们编写了调用$fatal的方法版本。这意味着我们的用户可能会在跑整个仿真时最后得到一个致命错误。这个在一个大型设计里可能得花上个半小时或者更长时间。

要是能更早的捕捉到这个错误不是更好吗?这个实际上也是可以的。

我们可以在 SystemVerilog里定义一种叫抽象类的东西。抽象类只能用来做基类,你不能用抽象类来例化一个对象,不然你会得到一个运行时错误。

在定义抽象类时,你可以把方法定义为纯虚方法。这些方法没有实体,而且在重载类时需要强制重载这些方法,如果不重载的话会得到编译错误。

抽象类和纯虚函数对继承抽象基类的工程师进行了强制规范。纯虚函数说,"你想用我的基类吗?可以的。这里写了你需要做什么事情的条款。"

我们定义了抽象类animal,纯虚函数make_sound( ),那么我们为什么不用为make_sound()写实体呢,因为重载类会去处理。

virtualclass animal;
   int age=-1;

   functionnew(int a);
      age = a;
   endfunction : new

   purevirtualfunctionvoid make_sound();

endclass : animal


class lion extends animal;

   functionnew(int age);
      super.new(age);
   endfunction : new

   functionvoid make_sound();
      $display ("The Lion says Roar");
   endfunction : make_sound

endclass : lion


class chicken extends animal;

   functionnew(int age);
      super.new(age);
   endfunction : new

   functionvoid make_sound();
      $display ("The Chicken says BECAWW");
   endfunction : make_sound

endclass : chicken


module top;


   initialbegin
   
      lion   lion_h;
      chicken  chicken_h;
      animal animal_h;
   
      animal_h = new(3); 
      
      lion_h  = new(15);
      lion_h.make_sound();
      $display("The Lion is %0d years old", lion_h.age);
      
      chicken_h = new(1);
      chicken_h.make_sound();
      $display("The Chicken is %0d years old", chicken_h.age);

      animal_h = lion_h;
      animal_h.make_sound();
      $display("The animal is %0d years old", animal_h.age);
      
      animal_h = chicken_h;
      animal_h.make_sound();
      $display("The animal is %0d years old", animal_h.age);
      
   end// initial begin

endmodule : top

下一章将介绍静态变量静态方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值