systemverilog中$cast类型向下转换和虚方法

本文探讨了面向对象编程中的继承概念,详细解释了当父类句柄指向子类对象时,如何通过$cast进行类型转换。同时,介绍了虚方法的作用,说明了使用virtual关键字如何确保调用正确的方法。通过示例展示了非虚方法和虚方法在调用上的区别,强调了对象类型而非句柄类型在决定方法调用上的关键作用。
摘要由CSDN通过智能技术生成

当使用继承来扩展类的功能的时候,需要一些OOP技巧来控制对象和功能。
如果将子类句柄赋值给父类句柄时,编译器则认为赋值是合法的,但分别利用子类句柄和父类句柄调用相同对象的成员时,将可能有不同的表现。
例1:不加virtual的function

class Transaction;
	rand bit [31:0] src;
	function void display(input string = "");	//没有virtual
		$display(%s Transaction: src = %d", prefix, src);
	endfunction
endclass
class BadTr extends Transaction;
	bit [31:0] src;
	bit bad_crc;
	function void display(input string prefix = "");	//没有virtual
		$display("%s BadTr: bad_src = %b", prefix, bad_crc);
		super.display(prefix);
	endfunction
endclass
Transaction tr;
BadTr 	bad, bad2, bad3;
//第一种情况
bad = new();				//构建BadTr扩展对象
tr = bad;					//将子类句柄赋值给父类句柄
$display(tr.src);			//显示基类对象的成员变量
tr.display();				//Transaction::display()
tr.src;					//基类的src
bad.src						//子类的src
bad.bad_src;				//子类的bad_src
bad.super.src;				//基类的src

通过tr找不到子类的src,虽然tr指向子类的对象,但是tr能查找到的范围只是父类范围的对象;
当一个类被扩展时,所有的基类变量和方法被继承,所以整数变量src存在于扩展类对象中。

//第二种情况
tr = new();		//创建一个父类
bad2 = tr;		//编译错误
$display(bad2.bad_crc);	//bad_crc成员不在父类对象中

如果你将一个基类对象直接拷贝到一个扩展类的句柄中,会发生操作失败,因为有些属性仅仅存在于扩展类中,基类并不具备。systemverilog编译器对句柄类型做静态检查。

//此时可以通过\$cast实现,$cast(bad, tr),如下所示:
//第三种情况
bad = new();
tr = bad;
$cast(bad2, tr);
$display(bad2.bad_crc);	//bad2指向的对象包括bad_crc
bad2.display();	//子类的BadTr::display()

类型向下转换或者类型变换是指将一个指向基类的指针转换成一个指向派生类的指针。
1、将一个父类句柄赋值给一个子类句柄并不总是非法的;但是systemverilog编译器对这种直接赋值的做法是禁止的,也就是无论父类句柄是否真正指向一个子类对象,赋值给子类句柄时,编译(静态)都将出现错误。因此需要$cast(target, source)来实现句柄类型的动态转换;
2、$cast不仅仅检查句柄本身,还会检查句柄所指向的的对象类型。注意:指向父类对象的父类句柄不能转换为子类句柄,指向子类对象的父类句柄可以转换为子类句柄。
3、一旦源对象跟目的句柄是同一类型,或者是目的句柄的扩展类,$cast()函数执行成功会返回1,否则返回0。

虚方法:
例2: 加virtual的function函数
(将类中的子程序定义成virtual, 这样就可以在扩展类中重定义。这一点适用于所有的任务和函数,除了new函数。因为new函数在对象创建时调用,所以无法扩展。systemverilog始终基于句柄类型来调用new函数。)

class Transaction;
	rand bit [31:0] src, dst, data[8];
	bit [31:0] crc;
	virtual function void calc_crc();
		crc = src ^ dst ^ data.xor;
	endfunction
endclass : Transaction
class BadTr extends Transaction;
	rand bit bad_crc;
	virtual function void calc_crc;
		super.calc_crc();
		if (bad_crc) crc = ~ crc;
	endfunction
endclass :BadTr
Transaction 	tr;
BadTr 			bad;
initial begin
	tr = new();
	tr.calc_crc;	//调用Transaction::calc_crc
	bad = new();
	bad.calc_crc;	//调用BadTr::calc_crc
	tr = bad;		//基类句柄指向扩展对象
	tr.calc_crc;	//调用BadTr::calc_crc
end

当需要决定调用哪个虚方法时,systemverilog根据对象的类型,而不是句柄的类型来决定调用什么方法。如例2最后一句tr.calc_crc.
如果没有virtual修饰符,systemverilog会根据句柄的类型而不是对象的类型来决定调用什么方法。如例1 tr.display().

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值