我有一些行为类似的代码:
class Base {};
class MyClass : public Base {};
MyClass* BaseToMyClass(Base* p)
{
MyClass* pRes = dynamic_cast<MyClass*>(p);
assert(pRes);
return pRes;
}
有没有办法添加编译时间检查所以我可以捕获对此函数的调用,其中p不是MyClass的实例?我看了看Alexandrescu的SUPERSUBCLASS功能,但我不确定它是否可以完成这项工作。
谢谢!
答案 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.StaticAssert和Boost.TypeTraits。前者可以被C ++ 0x中的内置static_assert
取代,而后者可以作为TR1以来的内置库。