如何确定C ++类是否有vtable?

时间:2011-05-11 20:39:13

标签: c++ vtable

我的一位朋友今天早些时候向我发出了以下挑战:

  

鉴于以下代码,建议OBJECT_HAS_VTABLE的实现,以便程序打印AnObject has a vtable = 0, AnObjectWithVTable has a vtable = 1

class AnObject
{
    int m_a;
    void DoSomething() {}

public: 
    AnObject() {m_a = 0;}
};

class AnObjectWithVTable
{
    int m_b;
    virtual void DoStuff() { }

public: 
    AnObjectWithVTable() {m_b = 0;}
};

void main()
{
    printf("AnObject has a vtable = %i, AnObjectWithVTable has a vtable = %i\n",
           OBJECT_HAS_VTABLE(AnObject),
           OBJECT_HAS_VTABLE(AnObjectWithVTable));
}

我想出了以下解决方案,我认为这个解决方案足够好了:

template <typename T>
bool objectHasVtable()
{
    class __derived : public T {};
    T t;
    __derived d;

    void *vptrT=*((void **)&t);
    void *vptrDerived=*((void **)&d);

    return vptrT != vptrDerived;
}

#define OBJECT_HAS_VTABLE(T) objectHasVtable<T>()

你们这些人和女孩能否为这个问题提出更好的解决方案?

享受! : - )

修改

解决方案不必在所有编译器中都是通用的。它可以在gcc,g ++,MSVC上工作......只需指定您的解决方案已知哪个编译器有效。我的是MSVC 2010。

3 个答案:

答案 0 :(得分:14)

标准方法是来自use std::is_polymorphic / TR1的Boost来确定一个类(及其基础)是否包含任何虚拟成员。

#include <type_traits>
#define OBJECT_HAS_VTABLE(T) (std::is_polymorphic<T>::value)

答案 1 :(得分:6)

为了完整起见,这是我哥们送给我的答案。从它的外观来看,它可能类似于TR1的工作方式(虽然我自己没有看过代码)。

template<class T>
class HasVTable
{
public :
    class _Derived_ : public T
    {
        virtual void _force_the_vtable(){}
    }
    enum { Value = (sizeof(T) == sizeof(Derived)) };
};

#define OBJECT_HAS_VTABLE(type) HasVTable<type>::Value

答案 2 :(得分:2)

您可以使用C ++的以下属性:

    如果参数不是多态类,则
  1. dynamic_cast在编译时失败。这种故障可以与SFINAE一起使用。
  2. dynamic_cast<void*>是有效的强制类型转换,它返回 complete 多态对象的地址。

因此,在C ++ 11中:

#include <iostream>
#include <type_traits>

template<class T>
auto is_polymorphic2_test(T* p) -> decltype(dynamic_cast<void*>(p), std::true_type{});

template<class T>
auto is_polymorphic2_test(...) -> std::false_type;

template<class T>
using is_polymorphic2 = decltype(is_polymorphic2_test<T>(static_cast<T*>(0)));

struct A {};
struct B { virtual ~B(); };

int main() {
    std::cout << is_polymorphic2<A>::value << '\n'; // Outputs 0.
    std::cout << is_polymorphic2<B>::value << '\n'; // Outputs 1.
}