dynamic_cast Template class with "Known" Inheritance - c++

I have a type that inherits from a template-defined type. The template-defined type is guaranteed to have a given base class. What I want to do is to be able to dynamic_cast or otherwise find types in a container that match my derived type, irrespective of the template parameter.
// A bunch of classes exist which inherit from Base already.
class Base{};
class Base2 : public Base {};
class BaseN : public Base {};
// Some new classes can inherit from any Base-derived class,
// but also have special attributes (i.e. function "f").
template<typename T = Base>
class Derived : public T
{
static_assert(std::is_base_of<Base, T>::value,
"Class must inherit from a type derived from Base.")
public:
void f();
};
//
// Now process a collection of Base pointers.
//
std::vector<Base*> objects;
// The vector may contain classes that are not "Derived".
// I only care about the ones that are.
// I want the cast here to return non-null for Derived<Base>,
// Derived<Base2>, Derived<BaseN>, but null for Base, Base2, etc.
// This will be Null, Good.
objects.push_back(new Base)
auto dcast0 = dynamic_cast<Derived<Base>*>(objects[0]);
// This will be Non Null, Good.
objects.push_back(new Derived<Base>);
auto dcast1 = dynamic_cast<Derived<Base>*>(objects[1]);
// This will be Null, BAD! HELP!
objects.push_back(new Derived<Base2>);
auto dcast2 = dynamic_cast<Derived<Base>*>(objects[2]);

As suggested by Creris' in comments, you need a base class is that is common to all your Derived<T> template classes when T is not Base. In addition, the inheritance to Base itself should be virtual, so that there is only a single Base instance when Derived<> is instantiated.
struct Base { virtual ~Base () = default; };
struct Base2 : virtual Base {};
struct DerivedBase : virtual Base {};
template <typename BASE = Base>
struct Derived : DerivedBase, BASE {};
Base *b = new Derived<Base2>;
assert(dynamic_cast<DerivedBase *>(b));
However, you could use template specialization so that the common base class is actually Derived<Base> itself.
struct Base { virtual ~Base () = default };
struct Base2 : virtual Base {};
template <typename = Base> struct Derived;
template <>
struct Derived<Base> : virtual Base {};
template <typename BASE>
struct Derived : Derived<Base>, BASE {};
Base *b = new Derived<Base2>;
assert(dynamic_cast<Derived<> *>(b));
Try it online!

Related

Inherit from arbitrary class in c++?

Is it possible to design a class that will inherit from any one of a group of base classes? I would like to be able to write something like:
class Derived : public ArbitraryBase {
public:
Derived () : ArbitraryBase () {}
...
};
where ArbitraryBase can be some base class determined at compile time. I have a group of base classes that I would like to derive identical classes from. Is there a way to avoid writing an individual derived class for each of the base classes?
If it is truly determined at compile time, you can make your derived class a template:
template<class T>
class Derived : public T {
public:
Derived() {}
...
};
You can later create instantiate this class by providing the base type:
int main() {
Derived< ??? > my_object;
...
}
Where ??? is some compile time way of getting your derived type.
You can do this via a template. Using
template<typename T>
class Derived : public T
{
public:
Derived() : T() {}
// or just use if actually need to provide a default constructor
Derived() = default;
};
gives you a class that inherits from T and calls T's default constructor. You would create a concrete class with it like
Derived<Base1> d;
and now d is a Derived that inherits from Base1.
If you need to inherit from an arbitrary number of bases then you can use a variadic template like
template<typename... Bases>
class Derived : public Bases...
{
public:
Dervied() : Bases()... {}
// or just use if actually need to provide a default constructor
Derived() = default;
};
and it would be used like
Derived<Base1, Base2, ..., BaseN> d;

reference data member to instantiations of template

I have a base class which is a template, and two derived classes like below,
template <class parm>
class Base{
};
class Derived1: public Base<Derived1>
{};
class Derived2: public Base<Derived2>
{};
Now I have another class holding a reference to Derived1 object or Derived2 object depending on which is passed into the constructor, but I don't know the syntax, is it achievable in C++?
struct Observer{
// I want to hold a reference to Derived1 or Derived2 based on
// which is passed into the constructor
template <class parm>
Base<parm> & derived_reference;
Observer(Derived1 & d1):derived_reference(d1) // what's the right syntax here?
{}
Observer(Derived2 & d2):derived_reference(d2)
{}
};
// I want to hold a reference to Derived1 or Derived2 based on
// which is passed into the constructor
template <class parm>
Base<parm> & derived_reference;
Given your class structure, that is not possible.
There is no common base class of Base<Derived1> and Base<Derived2>.
You can introduce another class as a base of Base<T> to pull off something that will be usable.
struct RealBase { virtual ~RealBase() {} };
template <class parm>
class Base : public RealBase {};
class Derived1: public Base<Derived1>
{};
class Derived2: public Base<Derived2>
{};
struct Observer{
RealBase& derived_reference;
Observer(Derived1& d1):derived_reference(d1)
{}
Observer(Derived2& d2):derived_reference(d2)
{}
};
That will be useful if you have virtual member functions in RealBase. Otherwise, you'll have to use dynamic_cast in client code for it to be useful.

Template base class can store pointers to derived but not objects - why?

I have the following code and I'm wondering why if I change the
T* e;
line to
T e;
it throws an error: "Base1::e' uses undefined class 'Derived'"
template<class T> class Base1
{
public:
Base1() {};
virtual ~Base1() {};
T* e;
};
class Base2
{
public:
Base2() {};
};
class Derived : public Base1<Derived>, Base2
{
public:
Derived() {};
~Derived() {};
};
For one thing, at the point where you specify that Derived inherits from Base1<Derived> your Derived class is not yet completely defined (aka. incomplete type) so the compiler can't instantiate it inside Base1. This is the reason why you're getting this specific error message.
But even if the compiler could instantiate a Derived at that point, what would happen? Base1<Derived> would contain a Derived which inherits from Base1<Derived> which contains a Derived which inherits... ad infinitum. Obviously this isn't valid.

templated typedefs and inheritance

I want to have a typedef in my base class to be specialized to each class derived from this base class. code:
template<class X>
class SharedPointer
{
public:
X* data;
SharedPtr(X *val)
{
data = val;
}
};
template<class T=Base> /* default type, I know this is a mistake.
The reason to have this here is to just indicate that the default argument
should be Base itself. so it'll have a Base type of shared pointer. */
class Base
{
public:
typedef SharedPointer<T> MyTypeOfPtr;
virtual MyTypeOfPtr Func()
{
Base *b = new Base;
return MyTypeOfPtr(b);
}
};
class Derived : Base<Derived>
{
public:
MyTypeOfPtr Func()
{
Derived *d = new Derived;
return MyTypeOfPtr(d);
}
};
main()
{
Base b;
Base::MyTypeOfPtr ptr1 = b.Func();
Derived d;
Derived::MyTypeOfPtr ptr2 = d.Func();
}
but this doesn't compile. is there a way to have this functionality?
You have to get all sorts of details right:
Spelling: "SharedPointer" or "SharedPtr"?
Templates and classes aren't the same thing, so you can't have class T = Base: T is a class, Base isn't. Also, you can't have the default refer to itself, so even class T = Base<T> doesn't work. Remove the default type.
Class inheritance is private by default, so say class Derived : public Base<Derived>.
Make the constructor of SharedPointer public.
Base::Func() makes no sense; maybe it should say new T.
I should seriously suggest that you start with simpler examples and build up slowly.

How to inherit a templatised Base class?

I am new to STL. I have written a Template Base class as follows
template <class T>
class Base
{
public:
//Constructor and Destructor ..
Base();
virtual ~Base();
virtual foo() = 0;
};
Now , I want to design my framework such that my inherited classes will be publicly derived from this class and will implement foo in their respective implementations. Problem is that I don't know how to inherit from a Template Base class ?
Is it as below ...
template class<T>
class Derived : public Base<T>
{
// Implementation of Derived constructor etc and methods ...
};
or Normal C++ way
class Derived : public Base
{
};
Any suggestions ? Also, I would appreciate for any information for getting started with STL for newbies like me ...
Regards,
Atul
The later,
class Derived : public Base
will not work, because Base is not a class, it's a class template. Than it depends on whether Derived should be a template or whether it should inherit particular instance of Base:
Template:
template<typename T>
class Derived : public Base<T>
Non-template:
class Derived : public Base<Something>
(where Something is some concrete type like int or char * or std::string)
Either
template class<T>
class Derived : public Base<T>
{ };
if you want Derived to work with Base<>s of any type.
Or
class Derived : public Base<SomeSpecificType>
{ };
if you want Derived to only work with a specific type of Base<>.
Your second example is the way to go.
template class<T>
public Base<T>
{ // Implementation of Base constructor etc and methods ...
};
template class<T>
class Derived : public Base<T>
{ // Implementation of Derived constructor etc and methods ...
public:
Derived() : Base<T>() { } //have to construct the proper instanciation of Base
};
Apart from the above answers, also be aware that it can be in following ways also:
template<typename T>
class Derived : public Base<Something> // Something is some concrete type
or
template<typename T, typename U>
class Derived : public Base<U>