c++ – Whether the pointer type inherits from a specific base type

Question:

Is there a way in C++ to determine if a pointer type is an inheritor of a particular base type? For instance:

template<class T>
void Foo(T *obj)
{
    if (Extends<Object>(obj))
        ...
    else
        ...
}

Answer:

C++11 introduced the is_base_of class template (in the type_traits file):

template< class Base, class Derived >
struct is_base_of;

This class has a static bool member named value . It is set to true if Derived is a derived type from Base (whether it's public , protected or private inheritance). And false otherwise. Also note that value is set to true if Base and Derived are the same type (doesn't work for fundamental types and pointers).
Here is an example code:

#include <iostream>
#include <type_traits>

using namespace std;

class A {};
class B : public A {};
class C : protected A {};
class D : private A {};
class F : public D {};
class Z {};

int main()
{
    cout << boolalpha;
    cout << is_base_of<A, B>::value << endl;
    cout << is_base_of<A, C>::value << endl;
    cout << is_base_of<A, D>::value << endl;
    cout << is_base_of<A, A>::value << endl;
    cout << is_base_of<A, F>::value << endl;
    cout << is_base_of<A, Z>::value << endl;

    return 0;
}

And we get the output:

true
true
true
true
true
false

C++17 introduces an auxiliary variable template:

template< class Base, class Derived >
inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;

It helps to avoid accessing the value member. With it, you can write like this:

cout << is_base_of_v<A, B> << endl;
cout << is_base_of_v<A, C> << endl;
cout << is_base_of_v<A, D> << endl;
cout << is_base_of_v<A, A> << endl;
cout << is_base_of_v<A, F> << endl;
cout << is_base_of_v<A, Z> << endl;

And we get the same output as before.
More details can be found here: https://en.cppreference.com/w/cpp/types/is_base_of


C++11 introduced the is_convertible class template (in the type_traits file):

template< class From, class To >
struct is_convertible;

It checks if the From type can be implicitly converted to the To type. This class, like is_base_of , has a static constant member value of type bool . It is set to true if the From type can be implicitly converted to the To type, and false otherwise.
Code example:

#include <iostream>
#include <type_traits>

using namespace std;

class A {};
class B : public A {};
class C : protected A {};
class D : private A {};

class X
{
public:
    operator A() { return a; }
private:
    A a;
};

class Y
{
public:
    explicit operator A() { return a; }
private:
    A a;
};

int main()
{
    cout << boolalpha;
    cout << is_convertible<A*, B*>::value << endl;
    cout << is_convertible<B*, A*>::value << endl;
    cout << is_convertible<C*, A*>::value << endl;
    cout << is_convertible<D*, A*>::value << endl;
    cout << is_convertible<X, A>::value << endl;
    cout << is_convertible<Y, A>::value << endl;

    return 0;
}

And output:

false
true
false
false
true
false

No explanation.
is_convertible<A*, B*>::value evaluates to false , because no down-converting is allowed in C++.
is_convertible<B*, A*>::value is true because implicit up-conversion is only allowed for public inheritance. For this reason, is_convertible<C*, A*>::value and is_convertible<D*, A*>::value yield false .
is_convertible<X, A>::value is true because class X has a conversion operator to A that can be called implicitly. It is not declared as explicit .
is_convertible<Y, A>::value evaluates to false because its conversion operator to A is declared explicit , and cannot be called implicitly.
C++17 introduces an auxiliary variable template:

template< class From, class To >
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;

It helps to avoid accessing the value member. With it, you can write like this:

cout << is_convertible_v<A*, B*> << endl;
cout << is_convertible_v<B*, A*> << endl;
cout << is_convertible_v<C*, A*> << endl;
cout << is_convertible_v<D*, A*> << endl;
cout << is_convertible_v<X, A> << endl;
cout << is_convertible_v<Y, A> << endl;

We get the same conclusion as before.
More details here: https://en.cppreference.com/w/cpp/types/is_convertible


In C++20, the derived_from concept should appear in the concepts file:

template< class Derived, class Base >
concept derived_from =
  std::is_base_of_v<Base, Derived> &&
  std::is_convertible_v<const volatile Derived*, const volatile Base*>;

More details here: https://en.cppreference.com/w/cpp/concepts/derived_from

Scroll to Top