Abstract base class using template argument from derived class - c++

I have a base class which provides pure virtual interfaces. I need this to store pointers to derived-class objects in a list of pointers to the base class.
The derived class is created using the template mechanism. The problem is now that if I want to have a virtual interface to return a type which is known only to the derived class, I need to pass it as a template argument as well. This is where the dilemma starts...
template <typename ITEM>
class base {
public:
virtual ITEM* get() = 0;
};
template <typename ITEM>
class derived : public base<ITEM>{
public:
ITEM* get() {...};
};
But when using a template in base I need to know this even when creating a list of base pointers:
base* myList[10] = {derived1, derived2,...}
Of course I don't know that type when I define my list. So I need to get rid of the template in my base class somehow.
EDIT: Got rid of this approach because it wasn't a useful approach at all. So no solution for this issue.

The code you write is not valid; there is not a single base type that is then parameterised like in Java, but a number of base<T> types. There is a way to obtain a wrapper for a truly generic object, and it is called "type erasure". It is used, for example in the implementation of boost::any.
Basically, you have a non-template base class with virtual functions, and then you make a template derived class that implements them. Note that the simplified version shown here does not work if you want to have an array of base objects, because base has pure virtual functions and thus cannot be instantiated (and because the T member of the derived type would be sliced off).
struct base;
template<typename T>
struct derived;
struct base {
virtual ~base();
// In this class we don't know about T, so we cannot use it
// Other operations that delegate to the derived class are possible, though
virtual std::size_t sizeofT() const = 0;
virtual const std::type_info& typeofT() const = 0;
// Since all you want is a pointer in "get", you could write it as a void*
virtual void* getPtr() = 0;
// Otherwise, we can implement this template function here that calls the virtual.
// Note that function templates cannot be virtual!
template<typename U>
U& getAs() {
// Verify that the type is the _same_ (no up/downcasts allowed)
// std::bad_cast is thrown here if U is not the same T used to build this object
derived<U>& meAsU = dynamic_cast<derived<U>&>(*this);
return meAsU.obj;
}
};
template<typename T>
struct derived : public base {
T obj;
// A couple of ctors to initialize the object, and the default copy/move ctors/op=
virtual ~derived();
derived(const T& o) : obj(o) {}
derived(T&& o) : obj(std::move(o)) {}
std::size_t sizeofT() const override {
return sizeof(T);
}
const std::type_info& typeofT() const override {
return typeid(T);
}
void* getPtr() override {
return static_cast<void*>(&obj);
}
};
If you want to use the base type directly as a variable, or in an array or container (vector, list, etc.), you need dynamic allocation - there are no two ways around it. You have two choices, which differ on where to place the responsibility for the dynamic allocation:
You can use the solution above if you limit yourself to having arrays of pointers to base. E.g. an array of std::unique_ptr<base>. The pointed-to objects would be of type derived<something>.
base err1; // Error, abstract class (what would it contain?)
base err2 = derived<int>(2); // Still abstract class, and the int would be sliced off
std::unique_ptr<base> ok(new derived<int>(3)); // Works
std::vector<std::unique_ptr<base>> objects;
objects.push_back(std::make_unique(new derived<int>(5)));
objects.push_back(std::make_unique(new derived<std::string>(2)));
int& a = objects[0].getAs<int>(); // works
std::string& b = objects[1].getAs<std::string>(); // works too
std::string& bad = objects[1].getAs<double>(); // exception thrown
Otherwise, you would have to implement the dynamic allocation in the base/derived classes themselves. This is what classes like boost::any or std::function do. The simplest any object would simply be a wrapper of an unique-ptr of the base class I showed here, with appropriate implementations of operators, etc. Then, you can have a variable of type any x = y; and the class would, inside its constructor, do the required new derived<Y>(y) required.

Related

Access derived class's method covariant return, with derived constructed from factory with unique_ptr<AbstractBase>

Edit: My question might just be asking how to downcast a unique_ptr<base> to unique_ptr<derived> (which is already answered), but I am not 100% sure what I am asking
I have an Abstract Base Class Base
class Base{
public:
Base();
struct pStruct{};
virtual pStruct pFunc(std::vector<double> data) = 0;
protected:
CustomType dataValue;
};
and two derived classes Derived1 and Derived2 that implement Base
class Derived1 : public Base {
public:
struct pStructD1 : Base::pStruct {
CustomType data1;
std::vector<double> data2;
};
Derived1(uint32_t foo1, std::vector<double> foo2, ...);
virtual pStruct pFunc(std::vector<double> data) override;
private:
uint32_t bar1{0};
};
class Derived2 : public Base {
public:
struct pStructD2 : Base::pStruct {
int32_t data3;
std::vector<double> data4;
double data5
};
Derived2(std::vector<double> foo1, std::vector<double> foo2, ...);
virtual pStruct pFunc(std::vector<double> data) override;
private:
std::vector<double> bar2;
};
When calling class method pFunc(std::vector<double> data), each derived class will return different types, and amounts of values. I tried making this work with a covariant return type, so Derived1::predict(data).key1 might be a matrix, and .key2 might be something else, and so on. Derived2::predict(data).key1 might be the only key, and it could be a boolean. Each derived class defines their own ::predict() return fields, because they vary significantly.
The issue is, I construct these derived classes with a factory, that reads some of the input (construction is via ifstream), and figures out what derived class it should be, and then calls the corresponding factory.
class BaseFactory {
public:
static std::unique_ptr<Base> createObj(std::ifstream & file){
file.read((char *) specificTypeString, 2);//This isn't actually the code, just assume this part works
if(specificTypeString == "D2"){
return D2BaseFactory::createObj(file);
}
else if(specificTypeString == "D1"){
return D1BaseFactory::createObj(file);
}
else{
throw std::runtime_error("error");
}
}
};
With std::unique_ptr<Base> D1BaseFactory::createObj(std::ifstream & file); returning std::unique_ptr<Derived1>(new Derived1(param1, param2, ...)); and the same thing for `D2BaseFactory'.
Problem is, if I construct a Derived class with the common BaseFactory, and call pFunc() on the returned unique_ptr, it always will be the empty Base::pStruct == {} and thus trying to access members of the covariant pStructs isn't possible. I know this is because the factory createObj returns the base type, but is there any way to dynamically return the type I want so I can access the necessary fields in the derived pStructs? I think using raw pointers might work, but if possible i'd like to keep them as unique pointers.
You can do something similar to this:
class Base
{
public:
...
std::unique<pStruct> pFunc(...) { return DopFunc(); }
protected:
virtual std::unique<pStruct> DopFunc() = 0;
};
class Derived1 : public Base
{
public:
struct pStructD1 : Base::pStruct { ... };
// Used when calling the child factory directly...
std::unique_ptr<pStructD1> pFunc(...)
{
return std::make_unique<pStructD1>(...);
}
protected:
// Used when called through the Base factory...
std::unique<pStruct> DopFunc(...) override
{
// Call the other function for code sharing... (DRY)
return pFunc(...);
}
....
};
This could make sense if you used the derived class when you need the derived objects.
The real question is why you need to used the derived types... If it is for initialisation purpose, then maybe the factory should do it before returning the value.
If it is for some processing, then maybe you should have some virtual functions in pStruct. That way, you never need to know the derived type returned by the factory.
In some case, the visitor pattern might also be a solution.
If you need to always use the specific struct, then why not always use the specific factory too?
You can also cast the result but if you need to do it every time you create an object, it might make the code more complex that it need to be.
Alternatively, you could also have a template member function let say template <class T> std::unique_ptr<T> pFuncT(...) { ... }. That way, the client code can specified the desired type directly at construction. An empty object or an exception could be throw if the type is incorrect.

How to implement a class template that provides functionality to its derived classes to track their instances?

I am trying to create an abstract class template (InstanceTracker) that classes can inherit from if they need functionality to perform operations on all of their instances. The class holds a static vector of pointers to 'T', and every time an InstanceTracker constructor is run, I push back a new pointer to the vector. I do this through a purely virtual getDerivedPtr() method that returns 'T*', that every class that derives from InstanceTracker has to implement with return this;. You can probably already see what is wrong what this though. You can never call a purely virtual function from a base constructor - since it doesn't exist yet. How can I find a way around this problem for my InstanceTracker class? Here's the code for the class:
#pragma once
#include <vector>
template <typename T>
class InstanceTracker
{
public:
InstanceTracker() noexcept
{
allInstances_.push_back(getDerivedPtr());
}
InstanceTracker(const InstanceTracker& source) noexcept
: InstanceTracker()
{
}
InstanceTracker(const InstanceTracker&& source) noexcept
: InstanceTracker()
{
}
virtual ~InstanceTracker() noexcept
{
auto it = std::find(allInstances_.begin(), allInstances_.end(), this);
int index = it - allInstances_.begin();
allInstances_.erase(allInstances_.begin() + index);
}
virtual T* getDerivedPtr() = 0;
protected:
static std::vector<T*> allInstances_;
};
If you want to try to run the code and see why it doesn't work at the moment, here's a simple class that inherits from InstanceTracker:
class Derived1 : public InstanceTracker
{
public:
Derived1* getDerivedPtr() override
{
return this;
}
};
You'd probably be better off using composition rather than inheritance, but I'll assume you have have a good reason to prefer inheritance here.
The difficulty is that, when a base class constructor is run, the this pointer is a pointer to an instance of the base class only. The derived instance doesn't even exit yet. (Likewise, on destruction, the derived portion of the object has already been uninitialized). So if you call a virtual method, you'll get the base class implementation rather than the derived class's implementation. In your case, the base class implementation doesn't even exist, so you're stuck.
You can probably get away with casting the base class's this pointer to a pointer to the derived class, but that's not guaranteed to work and probably involves undefined behavior.
One way to solve this is to store pointers to the base type (InstanceTracker *) rather the pointers to the derived type. Then your getDerivedPtr method doesn't need to be virtual, and it can do the cast when it's safe.
template <typename T>
class InstanceTracker {
public:
InstanceTracker() noexcept {
allInstances_.push_back(this);
}
// other constructors elided for space
virtual ~InstanceTracker() noexcept {
std::erase(
std::remove(allInstances_.begin(), allInstances_.end(),
this),
allInstances.end());
}
T* getDerivedPtr() {
return static_cast<T*>(this); // downcast
}
protected:
// allInstances_ stores base class pointers
static std::vector<InstanceTracker*> allInstances_;
};
Notes:
If you use RTTI, run-time type identification, you can use dynamic_cast instead of static_cast. You should not use a reinterpret_cast because the compiler might need to adjust the base pointer as part of the cast.
You're likely to run into problems if you create an instance of a derived type as const.

Check for template class equality through base class pointer

Is it possible to check, through a base class pointer, whether different derived template classes are specialization of the same template class?
This is achievable through introducing an intermediate non-template base-class. However, i would like to know whether this pattern is avoidable when the sole purpose of this intermediate class is for identification:
class A{}
class B_base : public A{}
template<T>
class B : public B_base {}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B through a
// dynamic_cast to the intermediate class
if(dynamic_cast<B_base*>()){
// This is a B_base object,
}
}
}
Ideally, i would like something like this, to avoid the intermediate class.
class A{}
template<T>
class B : public A{}
// There may be other derived classes of A
template<T>
class C: public A{}
void main() {
// ... some vector of pointers to A derived objects
std::vector<A*> v;
for(auto& i : v){
// Check whether i is any specialization of B
if(templateTypeId(i) == templateTypeId(B*)){
// This is a B object with some unknown specialization
}
}
}
Different specializations of a template are entirely unrelated types for most purposes. Template argument deduction can deduce a template and its arguments from such a type, but that happens entirely at compile time. There is no guaranteed run time information that can tell whether a class is a specialization of a given template, whether two classes are specializations of the same template, etc.
So you would need to set up a way to test this yourself, but your intermediate class method is not the only option. The most straightforward way would be to put a way to test it into the base A class:
class A {
public:
virtual ~A() = default;
virtual bool is_B() const noexcept { return false; }
};
template <class T>
class B : public A {
public:
bool is_B() const noexcept override { return true; }
};
Though this gets a bit ugly if there are several different B-like categories to test for, and doesn't work if it should be possible to extend A with new subtypes, and then test for those subtypes in a similar way.
Another idea would be to associate the type check with an object address:
struct type_tag {
constexpr type_tag() = default;
type_tag(const type_tag&) = delete;
type_tag& operator=(const type_tag&) = delete;
};
class A {
public:
virtual ~A() = default;
virtual bool matches_type(const type_tag&) const
{ return false; }
};
inline constexpr type_tag B_tag{};
template <class T>
class B {
public:
bool matches_type(const type_tag& tag) const override
{ return &tag == &B_tag; }
};
This pattern also allows for categories of subtypes that don't come from just one template. It also doesn't prevent a new class from "lying" about its own type, if that might be a concern, but it might be best not to try to prevent that, but let any implemented derived class be responsible for its own behavior, which might mean it wants to act "almost exactly like" some other type.
May be a better design is to add required virtual functions to interface A, so that you can invoke them directly on A* without guessing the derived class. The latter is an anti-pattern because it defeats the purpose of polymorphism: the idea that a piece of code can work with object of different classes without knowing their exact type. You may as well put objects of different types into different containers and not use ploymorphism based on virtual functions at all.

Casting specialized base pointer to derived pointer that specializes on additional template parameter ("adding on" a specialization)

I'd like to cast a base class pointer to a derived one in order to take advantage of some methods unique to the derived class. Here's an Ideone of a simple example that works:
template<typename A>
class Base {};
template<typename A, typename B>
class Derived : public Base<A> {
public:
void doSomething() {}
};
int main() {
Base<int>* foo = new Derived<int, double>;
static_cast<Derived<int, double>*>(foo)->doSomething();
return 0;
}
Now, the problem is that my foo is actually a member of a templated class,
template<typename A>
class Container
{
public:
Base<A>* foo;
};
and at the time I cast, I don't know what A is:
int main() {
Container<int> container;
container.foo = new Derived<int, double>;
// a lot of code later...
static_cast<Derived< /* ??? */ , double>*>(container.foo)->doSomething();
return 0;
}
Then I thought this might be possible if I could somehow store what A is in my base class, like
template<typename A>
class Base
{
public:
static type template_type = A; // made-up syntax
};
so that I can refer to it like
static_cast<Derived<container.template_type, double>*>(container.foo)->doSomething();
but according to this question it's not possible to store types in C++.
How do I achieve this cast without knowing A?
That is, how do I cast a specialized base pointer to a derived pointer that specializes on an additional template parameter? In less technical terms, I just want to take a Base pointer and tack on the other specialization necessary to form the Derived pointer.
Usually it is not wise to do an up-cast and there is usually a better design that you may use to avoid the need of up-cast at all, but if you really need it, then you may use dynamic_cast to do this.
this operator try to convert from one type to another type dynamically and if conversion is not possible, it will return nullptr. But remember that it only work for polymorphic types(types that have at least one virtual function) so in this case your Base class must be polymorphic(since you are holding a pointer to base class, you possibly need a virtual destructor to allow delete to work on base pointer and this make Base a polymorphic class).
But to remember a type in C++, you have 2 options:
Use typedef:
You may use typedef to hold type information in the class:
template< class A >
class my_class
{
public:
typedef A input_type;
};
template< class T >
void do_something(T const& t)
{
typename T::input_type n;
do_something_on_input_type(n); // possibly overloaded for different input types
}
this approach is really fast and have no overhead in runtime, but you can use it only in cases when you want to do something in compile time. and if the type of pointer is not determined until runtime this approach is not useful.
Use std::type_info
Using this you can actually hold type information with the class:
class Base { virtual std::type_info const& get_type() const = 0; };
class Child : public Base
{
virtual std::type_info const& get_type() const { return typeid(Child);
void child_specific_function() { /**/ }
}
class ChildOfChild : public Child
{
virtual std::type_info const& get_type() const { return typeid(ChildOfChild); }
// ...
};
void do_something(Base* base)
{
if (base->get_type() == typeid(Child))
{
static_cast<Child*>(base)->child_specific_function();
}
}
This sound really interesting but, it is only useful when you know exact type of the object and it does not work for derived types, so this approach work for Child but not for ChildOfChild

Is it possible to make a non-virtual create method

#include <memory>
class Base
{
std::shared_ptr<Base> create() const; // Returns a default constructed object
}
Suppose, that all the members derived to whatever degree from Base are copy constructible and default constructible. I want the
std::shared_ptr<Base> create() const;
Method to create object of the appropriate dynamic type, but I do not want to use boilerplate code.
Is it possible to make
std::shared_ptr<Base> create() const;
Statically bound, but inside find somehow the correct type and create the object using Default constructor? Possibly using C++11.
The create() functions should probably be static, as you don't have an instance yet. But without parameters you cannot do what you want... unless you use templates, of course:
class Base
{
public:
template<typename T>
static std::shared_ptr<Base> create() const
{
return std::shared<Base>(new T);
}
};
Then use it this way:
std::shared_ptr<Base> ptr(Base::create<Foo>());
Or, if you prefer:
std::shared_ptr<Base> ptr(Foo::create<Foo>());
Ideally you have a static and perhaps a non-static create() functions. There is a clever way to accomplish this.
Define a SuperBase class. It needs a virtual destructor and a pure virtual create() function. You'll use pointers/references to this class for normal late-binding OOP behaviours.
Define a Base class template that inherits from SuperBase. Base's template parameter will be the type of the Derived class. Base will also have a traits class template with a static function called create(). This static create() function will create a default object with new. Using the trait's create() function, Base will define both a static_create() and the pure virtual SuperBase::create() functions.
Implement Derived by inheriting from Base<Derived>.
One this is done, if you know you are using a derived type, then you can write Derived::create() to statically create a new one. If not, then you can always use an instance's create() method. Polymorphism is not broken since SuperBase would have the polymorphic interface you need/want --Base<D> is simply a helper class that auto defines the static_create() and create() functions so you would not normally use Base<D> directly.
Sample code appears below:
#include <memory>
#include <iostream>
class SuperBase
{
public:
virtual ~SuperBase() = default;
virtual std::shared_ptr<SuperBase> create() const = 0;
};
template <typename T>
struct Base_Traits
{
static T* create()
{
return new T;
}
};
template <typename Derived, typename Traits=Base_Traits<Derived>>
class Base : public SuperBase
{
public:
// Define a static factory function...
static std::shared_ptr<SuperBase> static_create()
{
return std::shared_ptr<SuperBase>{Traits::create()};
}
// Define pure virtual implementation...
std::shared_ptr<SuperBase> create() const override
{
return static_create();
}
};
class Derived : public Base<Derived>
{
};
int main()
{
auto newone = Derived::static_create(); // Type known # compile time
auto anotherone = newone->create(); // Late binding; type not known # compile time
}