如何确定 C++类有一个虚函数表吗?

发布于 2024-11-06 19:00:51 字数 1104 浏览 1 评论 0原文

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

给定以下代码,提出 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。

A friend of mine sent me the following challenge earlier today:

Given the following code, propose an implementation of OBJECT_HAS_VTABLE so the program prints 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));
}

I've came up with the following solution which I think is decent enough:

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>()

Is there a better solution to this problem?

Edit

The solution doesn't have to be generic across all compilers. It can work on gcc, g++, MSVC... Just specify for which compiler your solution is known to be valid. Mine is for MSVC 2010.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

悸初 2024-11-13 19:00:51

标准方法是 使用 std::is_polymorphic来自 C++11/C++03 TR1/Boost 以确定类(及其基类)是否包含任何虚拟成员。

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

The standard method is to use std::is_polymorphic from C++11/C++03 TR1/Boost to determine if a class (and its bases) contain any virtual members.

#include <type_traits>
#define OBJECT_HAS_VTABLE(T) (std::is_polymorphic<T>::value)
枯寂 2024-11-13 19:00:51

为了完整起见,这是我的朋友刚刚发给我的答案。从它的外观来看,它可能与 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

For completeness sake, here's the answer my buddy just sent me. From the look of it, it's probably similar to how TR1 does it (though I haven't looked at the code myself).

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
尤怨 2024-11-13 19:00:51

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

  1. 如果参数不是多态类,则 dynamic_cast 在编译时失败。此类故障可与 SFINAE 一起使用。
  2. dynamic_cast 是一个有效的转换,返回完整多态对象的地址。

因此,在 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.
}

You can use the following properties of C++:

  1. dynamic_cast fails at compile time if the argument is not a polymorphic class. Such a failure can be used with SFINAE.
  2. dynamic_cast<void*> is a valid cast that returns the address of the complete polymorpic object.

Hence, in 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.
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文