【问题标题】:How can abstract base class daemon call its pure virtual method?抽象基类守护进程如何调用它的纯虚方法?
【发布时间】:2014-05-08 05:48:32
【问题描述】:

从 ACE_Task_Base 派生的类(比如 A 类)有一个纯虚方法:

virtual int handler(int) = 0;

类 B 派生自类 A 并具有纯虚方法的实现。没问题。

现在,问题是:A类的守护线程调用这个纯虚方法:

int A::svc(void)
{
    while(true) {
        // some function;
        handler(void);
    }

    return 0;
}

如果方法是从 B 的对象调用的,那是没有问题的。但是,这个纯虚方法怎么能从A调用呢?

【问题讨论】:

  • 所以,您正在查看“这是如何发生的”,对吗?我会相应地修改问题...

标签: c++


【解决方案1】:

A 调用handler 将使用B 中提供的定义。

在任何地方调用纯虚方法都是安全的(在构造函数中除外),因为编译器会阻止您直接创建具有未实现的纯虚方法的对象。因此,您可以处理的任何对象都应该实现其所有方法,因此您不必担心这样的事情。

【讨论】:

  • 我想建议一个编辑——“你可以处理的任何对象都应该实现它的所有方法”——可以扩展为包括从构造函数调用函数的非常非常危险的做法。在纯虚拟的情况下,这会导致运行时崩溃。
  • @Sharadh,我简短地(但粗体地)提到了这个问题。你的评论仍然可以说剩下的。
【解决方案2】:

好吧,就像有人指出的那样,这会起作用。但是,它是如何工作的,需要深入了解 C++ 中继承是如何实现的。简而言之,纯虚函数告诉编译器“假设这个函数存在,稍后我会给你定义”。这种“稍后”发生在定义 B 时。这就是为什么您可以从 A 调用 A 中“不存在”的函数的原因。

函数的继承可以分解为简单的function signatures 到内存地址的映射(也称为vtablevirtual table 等)。

当普通函数被继承时,派生类添加到这个映射中。签名是否相同无关紧要,该类将添加一个新条目。更重要的是 - 它会以这样一种方式添加它,即这个“新”签名是为 Derived 类型的对象执行的。

但是,当Base 具有virtual 函数被继承时,Dervied替换映射条目,如果它找到相同的签名。这意味着任何试图在该对象上调用此签名的人现在都将调用新地址,即被覆盖的函数。这适用于所有虚函数。

纯虚函数是一种特殊情况,更多的是出于设计考虑。它们强制程序员实现某些功能,并在Interface 设计组件或Template 设计模式(以及其他)中找到用途。任何继承纯虚函数但不提供实现的类都不会被实例化——这将引发编译时错误。

关于构造函数的说明

函数的“入口”是在对象的构造过程中完成的。 Base 首先使用可用的信息构建,然后是 Dervied,然后覆盖 Base vtable 中的信息。 这意味着如果你从构造函数中调用虚函数,结果不是预期的。虚函数将解析为Base的定义,并且在纯虚函数的情况下,尝试取消引用空地址时崩溃。

【讨论】:

  • 感谢您的信息。现在,如果有两个类 B 和 C,它们从 A 派生并且每个都有 handler() 的实现(不同地),那么,在上述情况下,哪个 handler() 将被调用?
  • @user3614915 最具体/最近/派生的实现用于虚函数。如果它像“重写”一样工作,那么最后一次重写会得到调用,对吗?在您的情况下,如果A:foo() 是虚拟的并且 B,C 从 A 派生并实现 foo(),则指向 B 的 A 类型的 指针将调用 B:foo() 和 A 类型的指针指向 C 将调用 C:foo().
猜你喜欢
  • 1970-01-01
  • 2019-08-31
  • 1970-01-01
  • 1970-01-01
  • 2012-10-01
  • 2013-04-09
  • 2019-12-12
  • 2013-06-29
  • 1970-01-01
相关资源
最近更新 更多