接口,抽象类,虚方法,重写(interface,abstract class,virtual function,override)

本文详细解释了抽象类、虚方法的概念,并通过示例展示了它们如何实现多态性。通过对比抽象类与接口,阐述了各自的特点与适用场景。

1.抽象类和虚方法的区别(abstract,virtual function)

看到抽象和虚这两词真的觉得有点抽象,有点犯迷糊.其实这两者还是很容易区分的.

1.abstract可以修饰class和class中的成员.而且必须是class被abstract修饰了,里面的成员才能被abstract修饰.而virtual不能用来修饰class.只能用来修饰其中的成员.virtual可用于一般的class中,也可用于被abstract修饰的抽象类中.

2.抽象类不能被实例化.例如定义一个抽象类abstract class Dosomething() { };你这样去用肯定不行:Dosomething do = new Dosomething();

抽象类必须被继承并重写了其中的抽象方法才能被实例化.抽象方法里面是啥都没有的.只有个方法的定义在那,不能在里面去实现任何功能,然后必须在继承的子类中重写了才能用.而virtual方法不能只是个定义必须要实现.在继承的子类中可以被重写然后再用,也可以不重写直接用,用法和一般方法一样

2.为啥要搞个搞抽象类,抽象方法和虚方法出来呢?

虚方法和抽象方法可以用来实现多态,抽象类是实现和接口类似的功能.

一.首先说下多态吧.

我们知道面向对象的最主要的三个特性就是封装,继承,多态.多态简单的说就是通过继承创建的多个class,调用相同的方法(即返回类型,方法名,参数列表都相同.)实现了不同的功能.它是通过在继承中重写(override)相同的方法实现的.

另外有个词叫重载,那是指只参数名字相同.参数列表必须不同.

举个多态的简单例子吧:

//基类:

public class Person

{

public virtualvoid Do()

{

Console.WriteLine("Do something");

}

}

//继承的类:

public class Cheater:Person

{

public override void Do()

{

Console.WriteLine("Go to take money from some fools");

}

}

public class Killer:Person

{

public override void Do()

{

Console.WriteLine("Go to kill somebody");

}

}

Class PersonDo--测试类
{
Static void
Main(string[] args)

{

Person cheater = new Cheater();

cheater.Do();

Person killer = new Killer();

killer.Do();

}
}

--结果为:Go to take money from some fools

-- Go to kill somebody


我们也可以把基类改成抽象类,继承子类不变.运行结果跟上面一样.

public abstract class Person

{

public abstract void Do();

}

二.抽象类和接口的区别:

接口与抽象类有些相同的地方:

1.不能实例化 2.具有没有实现的方法.3.只有被继承的子类实现了没实现的方法才能实例化

不同点:

1.抽象类也是一种特殊的类.所有也只能单继承.接口则可以多继承

2.接口中的方法不能被public,private等修饰符修饰.它默认是为public.

3.接口除了可以包含方法之外,还可以包含属性、索引器、事件,而且这些成员都被定义为公有的。除此之外,不能包含任何其他的成员,例如:常量、域、构造函数、析构函数、静态成员

4.接口中的方法都不能实现.而抽象类可以实现一部分方法或者全部实现.就跟一般的class一样.

抽象类体现的是类的概念,是某一类事物的抽象,有该类事物的属性,及各种方法.而接口主要是某一组共同操作的集合.比如动物都有sleep,eat的方法.则可以定义一个接口,有sleep,eat两个方法.鸟类具有属性,两只脚,有羽毛.有方法飞行,下蛋.则可以定义一个抽象类.

其实只是为了设计的方便,清晰易懂而去做这样的考虑.你如果要把接口和抽象类不做区别的混淆使用,也完全是可以的.只要注意那些细微的语法区别.

<think>我们正在讨论UVM中的virtual function。根据用户提供的引用和之前的对话历史,用户已经对UVM中的virtual关键字有了一定的了解,特别是在virtual interface, virtual class, virtual sequence和virtual sequencer方面。现在用户想了解virtual function在UVM中的应用。 在面向对象编程(OOP)中,虚函数(virtual function)是实现多态的关键。在UVM中,虚函数主要用于允许用户在派生类中重写基类中的函数,从而实现运行时多态。 根据引用[1]:“virtual 是OOP中的一种关键字,主要体现的是多态。虚函数是指一个类中你希望重载的成员函数 ,当你用一个基类指针或引用指向一个继承类对象的时候,调用一个虚函数时, 实际调用的是继承类的版本。” 因此,在UVM中,virtual function的作用与标准OOP中的相同。它允许我们在基类中定义一个函数接口,然后在派生类中提供特定的实现。当通过基类句柄调用该函数时,将根据实际对象的类型调用相应的派生类实现。 在UVM中,虚函数常用于以下几个方面: 1. **回调函数(Callback functions)**:UVM提供了回调机制,允许用户在不修改原始代码的情况下插入自定义行为。这些回调函数通常是虚函数。 2. **工厂重载(Factory Override)**:UVM的工厂机制允许用派生类替换基类。当通过工厂创建对象时,如果派生类重写了基类的虚函数,那么将调用派生类的版本。 3. **UVM组件的自定义行为**:例如,在`uvm_component`中,`build_phase`、`run_phase`等相位函数都是虚函数,用户可以在自己的组件中重写这些函数以提供特定的行为。 下面,我们将详细说明UVM中虚函数的使用方法,并给出示例。 ### 1. **虚函数的声明和重写** 在SystemVerilog中,虚函数的声明使用关键字`virtual`,通常放在函数定义的前面。注意,在基类中声明为虚函数后,在派生类中重写时不需要再写`virtual`关键字(但可以写,通常不写),因为它是继承的虚属性。 示例: ```systemverilog class base_transaction extends uvm_sequence_item; `uvm_object_utils(base_transaction) function new(string name = "base_transaction"); super.new(name); endfunction // 声明一个虚函数 virtual function void display(string prefix=""); $display("%sBase: data=%0d", prefix, data); endfunction endclass class derived_transaction extends base_transaction; `uvm_object_utils(derived_transaction) function new(string name = "derived_transaction"); super.new(name); endfunction // 重写虚函数 function void display(string prefix=""); $display("%sDerived: data=%0d, extra=%0d", prefix, data, extra); endfunction endclass ``` ### 2. **多态行为** 当我们通过基类句柄指向派生类对象,并调用虚函数时,实际调用的是派生类中重写的函数。 ```systemverilog base_transaction base; derived_transaction derived; initial begin derived = derived_transaction::type_id::create("derived"); base = derived; // 基类句柄指向派生类对象 base.display(); // 调用的是derived_transaction中的display函数 end ``` ### 3. **在UVM回调中的应用** UVM回调是一种设计模式,它允许用户定义一些可插入的行为。回调函数通常是虚函数。例如,UVM的`uvm_callback`和`uvm_callbacks`类使用虚函数来定义回调接口。 例如,在driver中,我们可能希望有一个预驱动的回调: ```systemverilog class my_driver extends uvm_driver #(my_item); `uvm_component_utils(my_driver) // 声明一个虚函数,用于回调 virtual task pre_drive(); // 默认为空,用户可以在回调中重写 endtask virtual task run_phase(uvm_phase phase); forever begin seq_item_port.get_next_item(req); pre_drive(); // 调用虚函数,如果被重写则执行重写后的任务 drive_item(req); seq_item_port.item_done(); end endtask endclass // 用户定义的回调类 class my_driver_callback extends uvm_callback; `uvm_object_utils(my_driver_callback) virtual task pre_drive(); `uvm_info("CALLBACK", "Pre-drive callback called", UVM_MEDIUM) endtask endclass ``` 然后,用户可以将回调对象附加到driver实例上,这样在`pre_drive`调用时就会执行回调中的任务。 ### 4. **在UVM工厂中的应用** 工厂模式允许我们重载对象类型。当使用工厂创建对象时,如果派生类重写了基类的虚函数,那么通过基类句柄调用该函数将执行派生类的版本。 例如: ```systemverilog // 在测试中重载事务类型 set_type_override_by_type(base_transaction::get_type(), derived_transaction::get_type()); // 在某个地方创建事务 base_transaction trans; trans = base_transaction::type_id::create("trans"); // 实际创建的是derived_transaction trans.display(); // 调用derived_transaction::display ``` ### 5. **虚函数与纯虚函数** 在UVM中,有时也会使用纯虚函数(pure virtual function)。纯虚函数在基类中只有声明而没有实现,派生类必须实现它。纯虚函数使用`pure virtual`关键字声明。 例如,在UVM中,`uvm_report_object`类有一个纯虚函数`get_report_object`(实际上在UVM源码中可能有不同的设计,这里仅作示例): ```systemverilog virtual class abstract_component extends uvm_component; pure virtual function uvm_report_object get_report_object(); endclass ``` 注意:包含纯虚函数的类必须是抽象类(用`virtual class`声明),不能直接实例化。 ### 总结 在UVM中,虚函数是实现多态的重要机制,它允许在派生类中重写基类的函数,从而实现运行时绑定。虚函数广泛应用于UVM的回调、工厂重载以及组件的自定义行为中。 通过虚函数,UVM框架提供了灵活性和可扩展性,用户可以在不修改原有代码的基础上扩展功能。 §§相关问题§§ 1. UVM中虚函数和纯虚函数有什么区别? 2. 如何在UVM中使用回调(callback)机制? 3. UVM工厂机制如何与虚函数配合使用? </think>### UVM 中的虚函数(Virtual Function)详解 在 UVM 中,虚函数(`virtual function`)是实现多态性的核心机制,它允许在派生类中重写基类的方法。以下是关键概念和应用: #### 1. **基本概念** - **虚函数定义**:在基类中使用 `virtual` 关键字声明的函数,允许派生类重写方法。 - **多态实现**:当通过基类句柄调用虚函数时,实际执行的是**对象实际类型**的版本(动态绑定)。 - **与非虚函数区别**: - 非虚函数:编译时静态绑定,始终调用基类版本 - 虚函数:运行时动态绑定,调用对象的实际类型版本[^1] ```systemverilog class Animal; virtual function void sound(); $display("Generic animal sound"); endfunction endclass class Dog extends Animal; function void sound(); // 重写虚函数 $display("Bark!"); endfunction endclass // 测试 Animal a; Dog d = new(); a = d; // 基类句柄指向派生类对象 a.sound(); // 输出 "Bark!" (动态绑定) ``` #### 2. **在 UVM 中的关键应用** - **自定义事务处理**: ```systemverilog class BaseTransaction extends uvm_sequence_item; virtual function void modify_payload(); // 默认实现 endfunction endclass class CustomTransaction extends BaseTransaction; function void modify_payload(); // 重写 payload = payload ^ 8'hFF; // 自定义处理 endfunction endclass ``` - **组件行为扩展**: ```systemverilog class BaseDriver extends uvm_driver; virtual task pre_run(); // 默认预处理 endtask endclass class PCIeDriver extends BaseDriver; task pre_run(); // 重写 negotiate_speed(); // 特定协议处理 endtask endclass ``` - **回调机制基础**: 虚函数是 UVM 回调(如 `uvm_callbacks`)的实现基础,允许插入自定义行为而不修改原始类[^1]。 #### 3. **虚函数使用规则** 1. **声明位置**: ```systemverilog virtual function [return_type] function_name([args]); ``` 2. **重写要求**: - 派生类函数必须完全匹配签名(名称、参数类型、返回类型) - 可使用 `super` 调用基类实现: ```systemverilog function void modify(); super.modify(); // 调用基类方法 // 新增逻辑 endfunction ``` 3. **纯虚函数**: - 使用 `pure virtual` 强制派生类实现: ```systemverilog virtual class AbstractGenerator; pure virtual function void generate(); endclass ``` #### 4. **实际应用场景** - **协议适配**:在验证不同协议接口时,通过重写虚函数实现特定协议处理 - **调试增强**:重写 `do_record()` 或 `convert2string()` 添加自定义调试信息 - **功能覆盖**:在派生类中扩展覆盖率收集逻辑 - **模板方法模式**: ```systemverilog class ReportAnalyzer extends uvm_component; virtual function void analyze(); extract_data(); process(); // 虚函数,允许重写 store_results(); endfunction virtual function void process(); // 默认处理 endfunction endclass ``` #### 5. **最佳实践** 1. 在基类中为需要扩展的方法声明 `virtual` 2. 限制虚函数数量以避免过度复杂化 3. 使用 `protected` 访问控制保护关键实现 4. 结合 UVM 工厂实现动态对象替换: ```systemverilog BaseDriver drv; PCIeDriver pcie_drv = new(); drv = pcie_drv; // 工厂替换 drv.pre_run(); // 调用 PCIeDriver 版本 ``` > ⚠️ **注意**:虚函数引入的运行时绑定会轻微影响仿真性能,应在必要时使用。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值