jjzjj

(七)SV类的封装、继承、多态

小白菜~ 2024-06-07 原文

一、封装

封装只是一个概念,指的是把对象的属性和行为包在一起的思想,好处是保证了类内部数据结构的完整性,类外面只能执行该类允许公开的数据。

二、继承

类的继承指子类继承父类的成员变量和成员方法,使用关键字extends指明SV中一个子类不能有两个及以上的父类,一个父类可以有多个子类。示例:

typedef enum {RED,WHITE,BLACK} color_t;
class cat;
	//protect color_t color;
	color_t color;
	string name;
	//local bit is_good;
	bit is_good;
	
	function new();//若未自己定义new函数,则会自动调用super.new();函数
		this.is_good = 0;
		this.color = RED;
	endfunction
	
	function set_good(string ss,bit is_good);
		this.is_good = is_good;
		$display("%s is_good is %d",ss,this.is_good);
	endfunction

endclass

class black_cat extends cat;
	function new(string s1);
		this.name  = s1	  ;
		this.color = BLACK;
		$display("cat name is %s",name);
	endfunction
endclass

class white_cat extends cat;
	function new(string name);
		this.name  = name ;
		this.color = WHITE;
		$display("cat name is %s",this.name);
	endfunction

endclass

module test14;
	black_cat bk;
	white_cat wt;
	string s1 = "black_cat";
	string s2 = "white_cat";
	initial begin
		bk=black_cat::new(s1);
		wt=new(s2);
		bk.set_good(s1,1);
		wt.set_good(s2,1);
		$display("cat color is %s",bk.color);
		$display("cat color is %s",wt.color);
	end
endmodule

运行结果:
cat name is black_cat
cat name is white_cat
black_cat is_good is 1
white_cat is_good is 1
cat color is BLACK
cat color is WHITE

说明:

  1. 若类中没有写new函数(构造函数),那么系统会这个类自动添加一个默认的无参构造函数,是一个空函数体,只分配存储空间,不定义个性化的初值,每个没有继承关系的类都有且只有一个父类(object类),属于最高层次的类。
  2. 子类在定义new函数时,需要先调用父类的new函数或者super.new()。如果父类的new函数没有参数或者没有自定义new函数,子类也可以省略该调用,而系统会在编译时自动添加super.new()。
  3. 父类的new函数给父类变量方法开辟存储空间,子类的new函数给子类变量方法开辟存储空间,默认的new函数只负责开辟存储空间,不给个性化的初值,自定义new函数一般用于改变变量的初值,若自定义了new函数,则相当于重写了默认的new函数,也是多态的一种形式。
  4. super.属性(行为) :访问父类中的属性(行为) ;this.属性(行为) :访问本类中的属性(行为) ,关于this指针可以参考(六)SV的类、类的成员操作。

三、多态

多态:对方法同一种调用方式产生不同的结果,即当一个类派生出子类的时候,基类中的一些方法可能需要被重写,同名的方法。多态常见形式:虚方法、类型转换

一、虚方法:

  1. 关键字:virtual
  2. 在派生类中,重写该方法的时候必须采用 一致的参数和返回值
  3. 虚方法可以重写其所有基类中的方法,而普通的方法被重写后只能在本身及其派生类中有效。
  4. 在多层继承关系的类中实现了同一方法的虚方法,该虚方法只在最后一个派生类中有效。

示例:

class packet;
	int a =1;
	int b =2;

function void display_a;
	$display("packet::a is %0d",a);
endfunction

virtual function void display_b(bit [3:0] num1);
	$display("num1 is %0d",num1);
	$display("packet::b is %0d",b);
endfunction
endclass

class my_packet extends packet;
	int a =3;
	int b =4;
	
function void display_a;
	$display("my_packet::a is %0d",a);
endfunction

virtual function void display_b(bit [3:0] num2);
	$display("num2 is %5d",num2);
	$display("my_packet::b is %0d",b);
endfunction
endclass

module top;
	packet p1;
	my_packet p2;
initial begin
	p1=new();
	p2=new();
	p1 = p2;
	p1.display_a;
	p1.display_b(12);
end
endmodule

打印结果:
packet::a is 1
num2 is    12
my_packet::b is 4

说明:

  •    p1.display_a;display_a是普通方法,直接调用结束;p1.display_b;display_b是虚方法,调用 重写后的方法。

二、类型转换(也是多态的一种形式)

父类句柄指向子类,也就是子类转换为父类,是向上类型的转换

子类句柄指向父类,也就是父类转换为子类,是向下类型的转换

向上类型转换是安全的,向下类型转换是不安全的,因为父类本来在内存里就划好了一小块地盘,但是因为子类含有比父类更丰富的属性,它很有可能会访问父类并不包含的资源,所以会造成内存溢出。

向上类型转换:

示例:

class father;
	string m_name;
	
function new (string name);
	m_name = name;
endfunction

function void print ();
	$display("Hello %s", m_name);
endfunction

endclass : father

class child0 extends father;
	string car = "car";
	
function new (string name);
	super.new(name);
endfunction

endclass : child0

class child1 extends father;
	string plane = "plane";
	
function new (string name);
	super.new(name);
endfunction

endclass : child1

module top;
	father f;
	child0 c0;
	child1 c1;
initial begin
	f  = new("father");
	f.print();  //调用打印函数
	c0 = new("child0");
	f  = c0;   //父类指针指向子类
	f.print(); //调用同样的打印函数
	c1 = new("child1");
	f  = c1;   //父类指针指向子类
	f.print(); //调用同样的打印函数
end
endmodule : top

打印结果:
Hello father
Hello child0
Hello child1

说明:

  • 把父类指针指向子类,由于子类初始化变量的不同,所以printf函数,打印表现出不同的结果。

向下类型转换:

不能直接转换,可以通过动态类型转换函数$cast转换,但只有当前父类指针指向的对象和待转换对象的类型一致时,cast才会成功

class father;
	string m_name;
	
function new (string name);
	m_name = name;
endfunction

function void print ();
	$display("Hello %s", m_name);
endfunction

endclass : father

class child0 extends father;
	string car = "car";
	
function new (string name);
	super.new(name);
endfunction

endclass : child0

class child1 extends father;
	string plane = "plane";
	
function new (string name);
	super.new(name);
endfunction

endclass : child1

module top;
	father f;
	child0 c0;
	child1 c1;
	child1 c2;
initial begin
	f = new("father");
	f.print();
	c0 = new("child0");
	f = c0;
	f.print();
	c1 = new("child1");
	f = c1;
	f.print();
	c1.plane="big_plane";
	$cast(c2,f);//向下类型转换
	f.print();
	$write(", has %s",c2.plane);
end
endmodule : top

说明:

  • cast用于扩展内存空间,避免内存溢出,因为c2与c1类型相同,f指向了c1,所以最终c2是指向了c1,c2没有new过,所以在类型转换之前没有分配内存空间

有关(七)SV类的封装、继承、多态的更多相关文章

  1. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. 没有类的 Ruby 方法? - 2

    大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow

  4. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

  5. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

  6. ruby - 为什么当我调用类的实例方法时,初始化不显示为方法? - 2

    我正在写一篇关于在Ruby中几乎一切都是对象的博客文章,我试图通过以下示例来展示这一点:classCoolBeansattr_accessor:beansdefinitialize@bean=[]enddefcount_beans@beans.countendend所以从类中我们可以看出它有4个方法(当然,除非我错了):它可以在创建新实例时初始化一个默认的空bean数组它可以计算它有多少个bean它可以读取它有多少个bean(通过attr_accessor)它可以向空数组写入(或添加)更多bean(也通过attr_accessor)但是,当我询问类本身它有哪些实例方法时,我没有看到默认

  7. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

    我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

  8. ruby - 从外部访问类的实例变量 - 2

    我理解(我认为)Ruby中类变量和类的实例变量之间的区别。我想知道如何从该类外部访问该类的实例变量。从内部(即在类方法中而不是实例方法中),它可以直接访问,但是从外部,有没有办法做MyClass.class.[@$#]variablename?我没有任何具体原因要这样做,只是学习Ruby并想知道是否可行。 最佳答案 classMyClass@my_class_instance_var="foo"class上述yield:>>foo我相信Arkku演示了如何从类外部访问类变量(@@),而不是类实例变量(@)。我从这篇文章中提取了上述内

  9. ruby-on-rails - Resque - 类的未定义方法 'perform' - 2

    我目前对后台队列不太满意。我正在尝试让Resque工作。我已经安装了redis和Resquegem。Redis正在运行。一个worker正在运行(rakeresque:workQUEUE=simple)。使用Web界面,我可以看到工作人员正在运行并等待工作。当我运行“rakeget_updates”时,作业已排队但失败了。我已经用defself.perform和defperform试过了。发条.raketask:get_updates=>:environmentdoResque.enqueue(GetUpdates)end类文件(app/workers/get_updates.rb)c

  10. ruby-on-rails - rails 多态关联(遗留数据库) - 2

    我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint

随机推荐