Pure virtual function call error探讨

在实习的单位搞CxImage库时不知为什么在Debug时没有问题,但是Release版里竟然跳出个Pure virtual function call error! 啥东西呀,竟然遇上了,就探个究竟吧!

MSDN上的解释

http://forums.msdn.microsoft.com/zh-CN/clr/thread/bfa759a8-0cc0-4d65-8711-d2d0d6765687/

 

这时讲得很详细

http://www.artima.com/cppsource/pure_virtual.html

 

看看Codeproject上的一个例子

http://www.codeproject.com/KB/cpp/PureVirtualFunctionCall.aspx

 

(1)出现 Pure virtual function call 的原因是:

the child destructor is called and finished, so, we don’t have an object of type child now, but the current object (which is only being destructed) is of type Parent, so all calls in the destructor are calls to functions in this object. So, you can get a pure virtual function.

继承类的对象析构被调用,而且完成了释放,那么现在这个对象就不存在了,但是当前的对象(正在释构的父类对象)却要调用其子类的虚函数实现(因为自身是纯虚函数),所以就会出现Pure virtual function call error!

 

(2) 由面向对象的概念知,对象的析构是子类先析构再到父类析构,所以如果在父类中要调用自身的虚纯数将会很危险了,而且在是运行时出现的。

 

以下是codeproject的例子

 

Class Parent

{

public: Parent() { } 

~Parent() {  

ClearALL();  

}  

void ClearALL() 

{  

ThePure();   //调用自身的纯虚函数,包装一下是因为直接调用编译器会识别出这样调用是有问题的!

} 

 virtual bool ThePure() = 0 ;

}; 

class Child : public Parent

{

public: Child() { }  

~Child() { }  //The implementation of the pure virtual function  virtual bool ThePure()  

{  

return true; 

} 

};   

void main()

{

 Child c;

}

C析构时,虚函数表里的 ThePure()  已经注销,那么父类 Parent 里的ClearALL() 里的ThePure() 虚表指针就会指向一个空地址(成了 dangling pointer ), 所以在Parent里调用 ClearALL() 就会出错了

 

(3)如果上面的情况还算直观的话,看看下面的一种造成 pure virtual function call的情况就更隐蔽了。

//不过我在VC6里没有问题



class Base 

{

public:

    virtual void function() = 0;

};



class B : public Base



{

public:

    virtual void function() 

    {

        cout<<"pure function call in B"<<endl;



    }

};



class A 

{

public:

    A(B* b):_b(b) {}

    ~A() 

    {

        _b->function();

    }

    B* _b;

};



B b;

a(&b);



int main()

{

    return 0;

}

 

 

这种情况在某些编译器下会出pure virtual function call错误。主要的原因是因为全局变量的释放顺序不确定,全局变量A依赖全局变量B。如果编译器决定让B先释放,A后释放。那么,当A析构时,_b是一个dangling pointer。此时如果b对象的内存系统没有释放的话,那么bvptr表指向的是Basevptr,而不是B的。此时,_b->function()就指向pure virtual function了。详细情况可以到看看
     
http://www.cnblogs.com/whjiang/archive/2007/10/22/932880.html
   
(5)论坛上关于出现pure virtual function call 的情况总结:
   
     
   

1. 基类构造器直接调用虚函数

2. 基类析构器直接调用虚函数

3. 基类构造器间接调用虚函数

4. 基类析构器间接调用虚函数

5. Calling a virtual function via a dangling pointer.

(4)为了在遇到 pure virtual function call 时不致于程序蹦掉,可以实现在一基类的纯虚函数,但要记住找出原因后要删掉实现的代码
   
   

   
     
   
<think>我们正在讨论SystemVerilog中的纯虚类(pure virtual class)是否可以包含非纯虚函数(non-pure virtual function)。 根据SystemVerilog标准(IEEE 1800-2017): - 纯虚类(pure virtual class)是指包含至少一个纯虚方法(pure virtual method)的类。纯虚类本身不能被实例化。 - 纯虚方法(pure virtual method)是在类中声明但没有实现的方法,它只有原型(prototype),没有方法体。纯虚方法必须在非纯虚派生类中实现。 - 但是,一个纯虚类(即包含至少一个纯虚方法的类)也可以包含非纯虚方法(即具有实现的方法)以及数据成员。 因此,答案是:**可以**。纯虚类可以包含非纯虚函数(即具有实现的方法)以及数据成员。 示例: ```systemverilog virtual class PureVirtualBase; // 纯虚方法 - 必须在派生类中实现 pure virtual function void pureMethod(); // 非纯虚方法 - 有默认实现 virtual function void nonPureMethod(); $display("This is a non-pure virtual method in the pure virtual base class."); endfunction // 数据成员 int sharedData = 100; endclass class Derived extends PureVirtualBase; // 实现纯虚方法 virtual function void pureMethod(); $display("Derived class implements pureMethod."); endfunction endclass ``` 在这个例子中: - `PureVirtualBase` 是一个纯虚类,因为它包含纯虚方法 `pureMethod`。 - 同时,它也包含一个非纯虚方法 `nonPureMethod` 和一个数据成员 `sharedData`。 - 派生类 `Derived` 必须实现 `pureMethod`,但可以选择是否重写 `nonPureMethod`(如果不重写,则使用基类中的默认实现)。 使用: ```systemverilog module test; initial begin Derived d = new(); d.pureMethod(); // 输出: Derived class implements pureMethod. d.nonPureMethod(); // 输出: This is a non-pure virtual method in the pure virtual base class. $display("sharedData = %0d", d.sharedData); // 输出: sharedData = 100 end endmodule ``` 总结: - 纯虚类必须包含至少一个纯虚方法。 - 纯虚类可以包含非纯虚方法(有实现的方法)和数据成员。 - 纯虚类不能被直接实例化,只能通过派生类(该派生类实现了所有纯虚方法)来实例化。 这种设计允许我们在定义接口(强制子类实现某些方法)的同时,提供一些公共的默认实现和共享数据,从而提高代码复用性。 相关问题: 1. 在SystemVerilog中,纯虚类与抽象类(abstract class)有何异同异? 2. 纯虚类中的非纯虚方法是否可以被声明为静态方法(static)? 3. 如果纯虚类中包含非纯虚方法,那么该方法是否可以被声明为`final`? 4. 在UVM中,哪些地方使用了纯虚类同时包含非纯虚方法的特性?</think>在 SystemVerilog 中,**纯虚类(pure virtual class)完全可以包含非纯虚函数(non-pure virtual function)**。以下是关键要点和示例: ### 核心规则 1. **纯虚类定义** 只要类中包含**至少一个纯虚方法**(`pure virtual`),该类即成为纯虚类: ```systemverilog virtual class PureVirtualBase; pure virtual function void must_implement(); // 纯虚方法 virtual function void has_default() // 非纯虚方法 $display("Default implementation"); endfunction endclass ``` 2. **非纯虚函数特性** - 可以包含完整实现(方法体) - 子类**可选择重写或不重写** - 可通过基类指针直接调用: ```systemverilog PureVirtualBase obj = new Derived(); obj.has_default(); // 调用基类默认实现 ``` --- ### 完整示例 ```systemverilog virtual class Animal; // 纯虚方法 - 子类必须实现 pure virtual function void make_sound(); // 非纯虚方法 - 有默认实现 virtual function void breathe(); $display("Breathing..."); endfunction // 数据成员 int age; endclass class Dog extends Animal; virtual function void make_sound(); $display("Woof!"); endfunction endclass class Bird extends Animal; virtual function void make_sound(); $display("Chirp!"); endfunction // 重写非纯虚方法 virtual function void breathe(); $display("Fast breathing for flight"); endfunction endclass module test; initial begin Animal animals[$] = {new Dog(), new Bird()}; foreach(animals[i]) begin animals[i].make_sound(); // 多态调用 animals[i].breathe(); // 调用默认或重写实现 animals[i].age = 2; // 访问数据成员 end end endmodule ``` 输出: ``` Woof! Breathing... Chirp! Fast breathing for flight ``` ### 设计优势 1. **强制接口 + 可选实现** ```systemverilog virtual class NetworkProtocol; pure virtual function void send_packet(); // 必须实现 virtual function void log_error() // 可选重写 $display("Generic error"); endfunction endclass ``` 2. **代码复用** 基类中的非纯虚函数提供通用功能,减少子类重复代码。 3. **增量扩展** 新增方法时,现有子类无需立即实现: ```systemverilog virtual class Base; virtual function void new_feature() // 非纯虚 // 空实现或默认逻辑 endfunction endclass ``` --- ### 常见误区澄清 | 特性 | 纯虚类 | |---------------------|------------------------------------------------------------------------| | **是否可含数据成员** | 是(如示例中的`age`) | | **是否可含非纯虚方法** | 是(如`breathe()`) | | **是否可实例化** | 否(必须通过实现所有纯虚方法的子类实例化)[^2] | | **子类要求** | 必须实现所有纯虚方法,非纯虚方法可选重写 | --- ### 典型应用场景 1. **UVM 回调基类** ```systemverilog virtual class driver_callback extends uvm_callback; pure virtual task pre_tx(); // 必须实现 virtual function void log() // 可选重写 `uvm_info("CALLBACK", "Default log", UVM_LOW) endfunction endclass ``` 2. **协议抽象层** ```systemverilog virtual class bus_interface; pure virtual task read(); virtual function void reset() // 通用复位逻辑 $display("Executing bus reset"); endfunction endclass ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值