在编译时确定继承

时间:2010-07-19 08:00:18

标签: c++

我有一些行为类似的代码:

class Base {};

class MyClass : public Base {};

MyClass* BaseToMyClass(Base* p)
{
  MyClass* pRes = dynamic_cast<MyClass*>(p);
  assert(pRes);
  return pRes;
}

有没有办法添加编译时间检查所以我可以捕获对此函数的调用,其中p不是MyClass的实例?我看了看Alexandrescu的SUPERSUBCLASS功能,但我不确定它是否可以完成这项工作。

谢谢!

3 个答案:

答案 0 :(得分:4)

  

有没有办法添加编译时间检查所以我可以捕获对此函数的调用,其中p不是MyClass的实例?

通常,如果要在编译时检查它,可以将派生类作为参数。

但是,如果您拥有的只有Base*Base&,那么 就无法知道 是否引用{ {1}}对象。这是 运行时 多态的本质,可以在 运行时 中找到。只有在MyClass对象/引用/指针转换为MyClass / Base*的情况下才能进行此检查。这就是Base&被发明的原因。

您的功能基本上是dynamic_cast<>()。如果你把它放到正确的语法中,它看起来像这样:

safe_cast

答案 1 :(得分:2)

试试这个:

struct Base { virtual ~Base() {} };

struct MyClass : public Base {};

template <class T> MyClass* BaseToMyClass(T p) {
    int x[-(int)sizeof(T)];
    return 0;
}

template <> MyClass* BaseToMyClass(Base* p) {
    printf("1\n");
    MyClass* pRes = dynamic_cast<MyClass*>(p);
    assert(pRes != NULL);
    return pRes;
}

如果使用Base*调用该函数,将使用第一个特化。如果使用MyClass*调用它,则将使用通用版本。由于数组不能具有负大小,这将导致编译时错误,这可以追溯到实例化。

sizeof(T)是为了确保仅在实例化时显示错误。

请注意,如果Base包含您想要传递的任何其他子类,则此方法不适用。


使用示例:

int main () {           // 22
    MyClass p;          // 23
    Base q;             // 24
    BaseToMyClass(&q);  // 25
    BaseToMyClass(&p);  // 26
}                       // 27

结果

x.cpp: In function 'MyClass* BaseToMyClass(T) [with T = MyClass*]':
x.cpp:26:22:   instantiated from here
x.cpp:11:27: error: creating array with negative size ('-0x00000000000000008')

请注意,它无法检测到指针new的内容。例如,在

int main () {
    Base* p = new Base;
    Base* q = new MyClass;
    BaseToMyClass(p);
    BaseToMyClass(q);
    delete p;
    delete q;
}

程序将成功编译。

答案 2 :(得分:0)

(由于策略不同,我将此作为不同的答案发布。)

您可以使用静态断言来实现更灵活的约束,例如

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>

template <class T>
MyClass* BaseToMyClass(T* x) {
    BOOST_STATIC_ASSERT(!(boost::is_convertible<T, MyClass>::value));
    // ^ This ensures T is not MyClass at compile time.

    MyClass* p = dynamic_cast<MyClass*>(x);
    assert(p);
    return p;
}

错误消息类似于

x.cpp: In function 'MyClass* BaseToMyClass(T*) [with T = MyClass]':
x.cpp:26:22:   instantiated from here
x.cpp:13:1: error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>' 

请注意,如果您将指针声明为Base* p = new MyClass,它也无法检测到。

此代码使用Boost.StaticAssertBoost.TypeTraits。前者可以被C ++ 0x中的内置static_assert取代,而后者可以作为TR1以来的内置库。