【问题标题】:C++ Interview: vtable for a class with a pure virtual functionC++ 访谈:具有纯虚函数的类的 vtable
【发布时间】:2011-11-29 23:26:21
【问题描述】:

我今天被问到这个面试问题!! (这是一个非常尴尬的电话采访..):

vtable 与 virtual 的类有什么区别 函数和具有纯虚函数的类?

现在,我知道 C++ 标准没有指定任何关于 vtables 的内容,甚至没有指定 v-table 的存在......但是从理论上讲,答案是什么?

我脱口而出,具有纯虚函数的类可以有一个 vtable,其纯虚函数的 vtable 条目将指向派生类的实现。这个假设正确吗?我没有得到面试官的肯定回答。

假设的编译器会为只有纯虚函数的类创建一个 vtable 吗?如果类包含带有定义的纯虚函数怎么办? (如图:http://www.gotw.ca/gotw/031.htm)。

【问题讨论】:

  • 电话面试?你没有访问谷歌的权限吗?
  • 如果我是一名经理,并且我在电话面试中听到打字,我想我会立即让这个人失望:p
  • 我并没有说这是个好主意,或者我同意这样做。让我们面对现实吧,如果候选人不够聪明,无法掩饰他们使用谷歌的事实,你会雇用他们吗?
  • 掩饰自己的行为比使用谷歌要糟糕得多。我想知道有多少成功的工程师在不使用谷歌的情况下完成了一周的工作?一天怎么样?根据问题的答案采取行动也不会让你成为一名优秀的工程师,恰恰相反。
  • 我以前在电话面试中使用过谷歌,但我通常会觉得自己很脏。我宁愿说,“我不知道,我得查一下。”

标签: c++ virtual vtable


【解决方案1】:

在这种情况下,实现几乎可以做任何事情,因为如果 您的代码最终在上下文中调用纯虚函数 需要动态分辨率,它将解析为纯虚拟 函数,行为未定义。我见过几个不同的 解决方案:编译器插入一个函数的地址 以错误消息终止(来自 执行质量的观点),编译器插入一个空 指针,或者编译器从某个位置插入函数的地址 派生类。我还看到了编译器将插入 如果您提供实现,则为函数的地址。唯一的 这个问题的正确答案是你不能指望任何特定的 行为。

【讨论】:

    【解决方案2】:

    在非纯虚函数的情况下,vtable 中的每个条目将引用 final-overrider 或适应 this 指针的 thunk 如果需要。对于纯虚函数,vtable 中的条目通常包含一个指向泛型函数的指针,该泛型函数通过一些合理的消息抱怨和中止程序(在此调用的纯虚函数上下文或类似的错误消息)。

    假设的编译器会为只有纯虚函数的类创建一个 vtable 吗?

    是的,会的,不同之处在于存储在表格中的内容,而不是表格的形状。在一种简单的方法中,纯虚函数的 NULL 指针,虚函数的非 NULL 指针。实际上,指向一个泛型函数的指针会抱怨和abort() 与通常的编译器。

    如果类包含带有定义的纯虚函数怎么办?

    这不会影响 vtable。 vtable 仅用于动态调度,调用永远不会被动态调度到纯虚函数的定义(即您只能通过禁用限定类型名称的动态调度来手动调度到纯虚函数:@987654323 @ 会调用base::f,即使它是纯虚拟的,但如果它是纯虚拟的,x.f() 将永远不会被分派给base::f

    【讨论】:

    • 你只需要多重继承的thunk,不是吗?在单继承上,base 和 derived 从同一位置开始,因此无需适应 this
    • @eran:对,在线性继承层次结构中,所有具有虚函数的对象都可能具有相同的地址。
    • @MatthieuM:“在线性继承层次结构中,所有具有虚函数的对象都可能具有相同的地址”:为什么?
    • @MatthieuM.:只是一个空指针符合标准,但我知道的所有实现都添加了辅助函数。不知何故,提高实施质量唾手可得,为什么当您可以提供有关出了什么问题崩溃的信息时才触发崩溃?
    • @user7:thunk 仅在指向基类和派生类的指针不同的情况下才需要。在单继承关系中,base 子对象与derived 子对象对齐,这意味着(void*)static_cast<base*>(p) == (void*)p 其中p 是指向派生的指针(basederived 在内存中的位置重合)。当您有多重继承时,只有一个基可以与 derived 对象对齐,因此对于多个基之一,指针重合,但对于其余的,您需要更正 this 指针。
    【解决方案3】:

    我可以告诉您,Microsoft(和 MS VC++)将“纯”抽象类(仅具有纯虚函数的类)用于其 COM 接口。也许他是在说这件事。 COM 的“内部”表示是一个指向 vtable 的指针。 MS VC++ 中的纯抽象类以相同的方式实现,因此您可以使用它们来表示 COM 对象。显然,如果你的类有其他虚函数,你不能简单地用 COM vtable 覆盖它的 vtable :-)

    【讨论】:

    • IIRC,抽象类是具有一个或多个纯虚方法的类,而接口类是只有纯虚方法且没有成员变量的抽象类。现在,我从未在 C++ 中找到术语“抽象”和“接口”。我是从 C# 和 Java 推断出来的。
    • @paercebal 但是 C++ 中没有 interfaces :-) “正确”术语是 pure abstract class(我忘记写了 :-))
    • But there aren't "interfaces" in C++ :更具体地说,interface 关键字在 C++ 中不存在。这个概念确实存在,受到语言的支持,甚至与 Java 的 interface 相比得到了扩展。
    • @paercebal 观察我在评论中如何格式化interfaces :-) 诀窍就在那里。即使没有纯抽象类,您也可以拥有接口。接口主要存在于程序员的脑海中。每个虚拟方法都会抛出并且必须重载才能执行某些操作的类对我来说是一个接口。您不需要不是多态性的语言支持。您可以将 COM 与 C 一起使用,而 C 甚至没有类,而 COM 是基于接口的。正如我所说,接口在程序员的脑海中。该语言只能将它们标记为实例化它们的错误。
    猜你喜欢
    • 2015-10-24
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 2015-12-20
    • 2011-06-04
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    相关资源
    最近更新 更多