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.
Related
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;
I'm having trouble passing a class DerivedObject (part of class DerivedClass derived from template class BaseClass) derived from BaseObject (part of template class BaseClass) as a template argument to template class BaseClass.
This way, both Base and Derived classes have the access to the object pool, that can contain derived objects. This sounds a bit confusing, so here is the example:
template <class TDerivedClass, class TDerivedObject>
class BaseClass
{
protected:
class BaseObject
{
// Class implementation
}
void foo()
{
static_cast<TDerivedClass*>(this)->foo();
}
std::vector<TDerivedObject*> m_objectPool;
};
The above is the base class implementation.
error C2065: 'DerivedObject' undeclared identifier
The above error is cause by the first line of the class definition bellow:
class DerivedClass : public BaseClass<DerivedClass, DerivedClass::DerivedObject>
{
protected:
class DerivedObject : public BaseObject
{
// Class implementation
}
void foo()
{
// Method implementation
}
};
Is there a way to do this? If not, is there a better solution that would give me the same / similar functionality?
At this point
class DerivedClass : public BaseClass<DerivedClass, DerivedClass::DerivedObject>
The compiler has not seen DerivedClass::DerivedObject so you get an undeclared identifier error. As they type has not been seen you cannot use it as a template parameter. You don't get one for DerivedClass as you already have declared DerivedClass as a class.
You could change you base class and have it store a std::vector<BaseObject*> in it and if you do that then you can change your code to:
template <class TDerivedClass>
class BaseClass
{
protected:
class BaseObject
{
// Class implementation
};
void foo()
{
static_cast<TDerivedClass*>(this)->foo();
}
std::vector<BaseObject*> m_objectPool;
};
class DerivedClass : public BaseClass<DerivedClass>
{
protected:
class DerivedObject : public BaseObject
{
// Class implementation
};
void foo()
{
// Method implementation
}
};
Here is one way of doing something similar to what was requested:
#include <vector>
using std::vector;
template <class TDerivedClass, class TDerivedObject>
class BaseClass
{
public:
class BaseObject
{
// Class implementation
};
protected:
// void foo()
// {
// static_cast<TDerivedClass*>(this)->foo();
// }
// std::vector<TDerivedObject*> m_objectPool;
};
class DerivedClass;
class DerivedObject : public BaseClass<DerivedClass, DerivedObject>::BaseObject
{
// Class implementation
};
class DerivedClass : public BaseClass<DerivedClass, DerivedObject>
{
public:
void foo()
{
// Method implementation
}
};
From your example code, I get the impression that you want to provide different implementations for different base classes. Is there any special reason for using templates? If not, you could use classic polymorphism instead:
class BaseClass
{
class BaseObject {};
virtual ~BaseClass() {} // <- do not forget to provide virtual dtor!
virtual void foo() = 0;
std::vector<BaseObject*> m_objectPool;
};
class DerivedClass : public BaseClass
{
class DerivedObject : public BaseObject {/*...*/};
virtual void foo(){/*...*/}
};
Again, BaseObject would offer virtual or pure virtual functions - as you need.
One thing, however, you lose this way: the guarantee that in the vector there are always the objects of one specific BaseObject sub-type. If this matters for you, you could protect the pool and only allow to add new BaseObjects via DerivedClass. If this is not applicable, I might think up another solution from within BaseClass.
If you do not mind having the DerivedObject structure separately from the DerivedClass you may do something like that:
template <class T>
struct ObjectTypeTrait
{
static_assert(sizeof(T) == 0, "undefined trait");
};
template <class TDerivedClass>
class BaseClass
{
protected:
class BaseObject
{
// Class implementation
};
void foo()
{
static_cast<TDerivedClass*>(this)->foo();
}
std::vector<typename ObjectTypeTrait<TDerivedClass>::obj*> m_objectPool;
};
class DerivedClass;
class DerivedObject
{
// Class implementation
};
template<>
struct ObjectTypeTrait<DerivedClass>
{
using obj = DerivedObject;
};
class DerivedClass : public BaseClass<DerivedClass>
{
protected:
void foo()
{
// Method implementation
}
};
I do not claim this to be very brilliant solution, but you can get the idea - using type traits or typedefs
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!
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.
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>