Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test whether a class is polymorphic

We have a sub-project 'commonUtils' that has many generic code-snippets used across the parent project. One such interesting stuff i saw was :-

/*********************************************************************
If T is polymorphic, the compiler is required to evaluate the typeid 
stuff at runtime, and answer will be true.  If T is non-polymorphic, 
the compiler is required to evaluate the typeid stuff at compile time, 
whence answer will remain false
*********************************************************************/
template <class T> 
bool isPolymorphic() { 
   bool answer=false; 
   typeid(answer=true,T()); 
   return answer; 
}

I believed the comment and thought that it is quite an interesting template though it is not used across the project. I tried using it like this just for curiosity ...

class PolyBase {
public:
   virtual ~PolyBase(){}
};

class NPolyBase {
public:
   ~NPolyBase(){}
};


if (isPolymorphic<PolyBase>())
  std::cout<<"PolyBase = Polymorphic\n";
if (isPolymorphic<NPolyBase>())
  std::cout<<"NPolyBase = Also Polymorphic\n";

But none of those ever returns true. MSVC 2005 gives no warnings but Comeau warns typeid expression has no effect. Section 5.2.8 in the C++ standard does not say anything like what the comment says i.e. typeid is is evaluated at compile time for non-polymorphic types and at runtime for polymorphic types.

1) So i guess the comment is misleading/plain-wrong or since the author of this code is quite a senior C++ programmer, am i missing something?

2) OTOH, I am wondering if we can test whether a class is polymorphic(has at least one virtual function) using some technique?

3) When would one want to know if a class is polymorphic? Wild guess; to get the start-address of a class by using dynamic_cast<void*>(T) (as dynamic_cast works only on polymorphic classes).

Awaiting your opinions.

Thanks in advance,

like image 388
Abhay Avatar asked Jul 10 '09 06:07

Abhay


People also ask

What makes a class polymorphic?

Polymorphism means "many forms", and it occurs when we have many classes that are related to each other by inheritance. Like we specified in the previous chapter; Inheritance lets us inherit attributes and methods from another class.

What is a polymorphic class C++?

Polymorphism in C++ Typically, polymorphism occurs when there is a hierarchy of classes and they are related by inheritance. C++ polymorphism means that a call to a member function will cause a different function to be executed depending on the type of object that invokes the function.

Is C++ polymorphic?

What is Polymorphism in C++? Polymorphism in C++ means, the same entity (function or object) behaves differently in different scenarios. Consider this example: The “ +” operator in c++ can perform two specific functions at two different scenarios i.e when the “+” operator is used in numbers, it performs addition.


2 Answers

Since C++11, this is now available in the <type_traits> header as std::is_polymorphic. It can be used like this:

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

struct NPolyBase { 
  ~NPolyBase() {}
};

if (std::is_polymorphic<PolyBase>::value)
  std::cout << "PolyBase = Polymorphic\n";
if (std::is_polymorphic<NPolyBase>::value)
  std::cout << "NPolyBase = Also Polymorphic\n";

This prints just "PolyBase = Polymorphic".

like image 89
Tom 7 Avatar answered Oct 15 '22 20:10

Tom 7


One can use the facts that:

  1. dynamic_cast fails at compile time if the argument is not a polymorphic class. So that it 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.
}
like image 28
Maxim Egorushkin Avatar answered Oct 15 '22 18:10

Maxim Egorushkin