检查类是否从一个特定的类派生(编译,运行时两个答案可用) [英] Check if class is derived from a specific class (compile, runtime both answers available)

查看:111
本文介绍了检查类是否从一个特定的类派生(编译,运行时两个答案可用)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更容易解释一个例子,

  class base {
// ....
}

class derived1:public base {
// ...
}

在我的库中,有一个基类的指针。库的用户必须从base或derived1派生类,并将指针分配给该类。



如何检查用户定义类派生的类是什么?

解决方案

我对编译时x运行时解决方案有一些评论。除了评估它们之外, is_base_of dynamic_cast 有不同的要求,他们的答案可能不同。 >

(1)首先(如别人指出)使用 dynamic_cast 和派生类必须是多态的(必须至少有一个 virtual 方法)。 is_base_of 不需要类型为多态。



(2) is_base_of 的操作数都是类型,而 dynamic_cast 需要一个类型(< / code>)和一个对象(在()内)。



dynamic_cast is_base_of 可以给出不同的答案(或者可以编译而另一个不能)继承类型( public vs protected private )。例如考虑:

  struct B {virtual〜B(){}}; //多态,所以它可以在dynamic_cast中使用
struct D1:public B {}; // polymorphic by(public)inheritance
struct D2:private B {}; // polymorphic by(private)inheritance

D1 d1;
D2 d2;

我们有

  static_assert(std :: is_base_of< B,D1> :: value,); 
static_assert(std :: is_base_of< B,D2> :: value,);

assert(dynamic_cast< B *>(& d1));
assert(!dynamic_cast< B *>(& d2)); //注意否定。

实际上,最后一行会在GCC中产生编译器错误( error:'B '是'D2'的不可访问的基础)。 VS2010编译它(只产生类似于GCC的错误消息的警告)。



(4)对多态类的要求可以是通过异常处理技巧放松。请考虑:

  struct B {}; //没有多态性
struct D1:public B {}; // not polymorphic
struct D2:private B {}; // not polymorphic

D1 d1;
D2 d2;

template< typename B,typename D>
const B * is_unambiguous_public_base_of(const D * obj){
try {
throw obj;
}
catch(const B * pb){
return pb;
}
catch(...){
}
return nullptr;
}

然后我们有

  static_assert(std :: is_base_of< B,D1> :: value,); 
static_assert(std :: is_base_of< B,D2> :: value,);

assert((is_unambiguous_public_base_of< B>(& d1))));
assert(!(is_unambiguous_public_base_of>(& d2))); //注意否定。

值得一提的是 is_unambiguous_public_base_of dynamic_cast 和(这在下面更新中提到的重命名后变得更加明显)对于downcasts总是返回 nullptr

  B * b1 =& d1; 
assert(dynamic_cast< D1 *(b1)); //需要D1和B是多态的。
assert(!(is_unambiguous_public_base_of< D1>(b1))) //注意否定。

有关此技巧的过时参考是此处



免责声明:上面的 is_unambiguous_public_base_of 的实现只是一个草案,它不处理 const 和<$ c $

:在此帖子的以前版本

is_unambiguous_public_base_of
被命名为 my_dynamic_cast ,这是一个混乱的原因。所以我把它重命名为一个更有意义的名字。 (感谢Jan Herrmann。)


It is easier to explain on an example so,

class base {
//....
}

class derived1 : public base {
//...
}

In my library, there is a pointer of base class. The user of the library have to make classes derived from either base or derived1 and assign pointer to that class.

How can I check what class is user-defined class derived from?

解决方案

I have some remarks on the proposed compile-time x runtime solutions. In addition to when they are evaluated, is_base_of and dynamic_cast have different requirements and their answers can be different.

(1) First of all (as pointed out by others) to use dynamic_cast, base and derived classes must be polymorphic (must have at least one virtual method). is_base_of doesn't require the types to be polymorphic.

(2) The operands of is_base_of are both types whereas dynamic_cast needs a type (inside < >) and an object (inside ( )).

(3) dynamic_cast and is_base_of can give different answers (or one can compile while the other doesn't) depending on the type of inheritance (public vs protected or private). For instance consider:

struct B { virtual ~B() {} }; // polymorphic, so it can be used in a dynamic_cast
struct D1 : public B {};      // polymorphic by (public)  inheritance
struct D2 : private B {};     // polymorphic by (private) inheritance

D1 d1;
D2 d2;

We have

static_assert(std::is_base_of<B, D1>::value, "");
static_assert(std::is_base_of<B, D2>::value, "");

assert(dynamic_cast<B*>(&d1));
assert(!dynamic_cast<B*>(&d2)); // Notice the negation.

Actually the last line yields a compiler error in GCC (error: 'B' is an inaccessible base of 'D2'). VS2010 does compile it (yielding just a warning similar to GCC's error message).

(4) The requirements on the classes being polymorphic can be relaxed through an exception handling trick. Consider:

struct B { };             // not polymorphic
struct D1 : public B {};  // not polymorphic
struct D2 : private B {}; // not polymorphic

D1 d1;
D2 d2;

template <typename B, typename D>
const B* is_unambiguous_public_base_of(const D* obj) {
    try {
        throw obj;
    }
    catch (const B* pb) {
        return pb;
    }
    catch (...) {
    }
    return nullptr;
}

Then we have

static_assert(std::is_base_of<B, D1>::value, "");
static_assert(std::is_base_of<B, D2>::value, "");

assert((is_unambiguous_public_base_of<B>(&d1)));
assert(!(is_unambiguous_public_base_of<B>(&d2))); // Notice the negation.

It's worth mentionning that is_unambiguous_public_base_of is far slower than dynamic_cast and (this became more obvious after the renaming mentioned in the update below) always returns a nullptr for downcasts:

B* b1 = &d1;
assert(dynamic_cast<D1*>(b1));        // Requires D1 and B to be polymorphic.
assert(!(is_unambiguous_public_base_of<D1>(b1))); // Notice the negation.

A bit outdated reference on this trick is here.

Disclaimer: the implementation of is_unambiguous_public_base_of above is just a draft to make the point and it doesn't handle const and volatile qualifications properly.

Update: In a previous version of this post is_unambiguous_public_base_of was named my_dynamic_cast and this was a source of confusion. So I renamed it to a more meaningful name. (Thanks to Jan Herrmann.)

这篇关于检查类是否从一个特定的类派生(编译,运行时两个答案可用)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆