Is it possible to make a non-virtual create method - c++

#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
}

Related

Is there a way to have a member parameter type be a pointer to a derived class

I'm writing a module system for my program, where individual modules are initialised and shutdown by a system.
how this works is I call an Init() function that will initialise a static pointer of the class.
this works and is fine, however: I would like to abstract this into a class so the api is easier to maintain, but I don't know how to change the pointer type of the derived class automatically
for example, if I have the base class IModule:
class IModule {
public:
protected:
result Init();
result Shutdown();
private:
static IModule* s_instance;
};
is there a way I can write this class so that the derived class can be written as
class Derived : public IModule {
protected:
result Init();
result Shutdown();
}
and have Derived::s_instance evaluate to a Derived*
No, you can't have a variable whose type depends on the type of this. However, you can have a variable whose type depends on a template parameter.
template <typename T>
class IModule {
private:
static T* s_instance;
};
class Derived : public IModule<Derived> {
// The s_instance in this class is of type Derived*.
}
This is called the curiously recurring template pattern and it's used to do all sorts of tricks in C++. It may not work for your use case (for instance, you can no longer have a list of IModule which all have different derived types), but depending on what exactly you're doing this may be the way to go.
You can do this as long as the return types are covariant, i.e., Derived::Init() returns something derived from Derived::IModule()'s return type. Which is I think the case here. A simplified version:
#include <iostream>
struct IModule {
virtual IModule* Init() = 0;
private:
static IModule* s_instance;
};
class Derived : public IModule {
Derived* Init() override { std::cout << "1" << std::endl; return this; }
};
int main() {
IModule* ptr = new Derived();
ptr->Init(); // compile-time type: IModule, runtime: Derived
}

Defining variadic function specialization in child class

I am trying to allow a child class to define the variadic function specialization. For example:
#include <iostream>
#include <vector>
#include <memory>
class BaseClass
{
public:
BaseClass() {};
virtual ~BaseClass() {};
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
};
class ReceiveInt : public BaseClass
{
void ReceiveData(int & inData)
{
std::cout << "I know what to do!";
}
};
int main(int argc, char* argv[])
{
std::vector<std::shared_ptr<BaseClass>> classHolder;
classHolder.push_back(std::make_shared<ReceiveInt>());
int test = 1;
classHolder.front()->ReceiveData(test);
return 0;
}
But unfortunately this does not work, as the BaseClass ReceiveData function is called. Is this even possible?
EDIT 1
As people have pointed out, I'm very wrong with my notation. Looks like I learned more than I expected today.
Is this even possible?
I don't think so.
Dynamic dispatch is possible only for virtual member functions.
Member function templates may not be virtual.
If you can use regular member functions, i.e. not member function templates, then you can make them virtual. That will work.
You confuse some notions here.
To start with, there are no variadic templates here as ReceiveData function below:
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
is a template member function.
Then, if you want to override a method in the derived class, the right way is to use virtual functions, probably a pure virtual function in the base class and a virtual function with an override specifier in the derived class.
However, virtual functions limit you to a a set of fixed types because there are no template virtual functions. You could experiment with CRTP though:
template<typename T>
class Base {
public:
void receiveData(const T&) {}
};
class ReceiveInt : public Base<int> {};
which emulates a sort of static polymorphism. Below:
ReceiveInt{}.receiveData(int{});
receiveData from the base class instantiated with int.
I think you may be confusing your terminology. BaseClass::ReceiveData is a templated method, taking a template parameter GenericData. A variadic function takes a number of arguments determined at runtime.
In ReceiveInt, you're not making a specialization of anything, because ReceiveInt::ReceiveData is not a templated method. In fact, even if it was templated, it would not be possible to call in your example. How would a pointer to BaseClass know how to call a template specialization in the derived class it points to?
You can make BaseClass::ReceiveData virtual. This allows you to override it in a base class, and still call it with a pointer to BaseClass. Unfortunately, templates are a compile time language feature, whereas dynamic dispatch is a runtime feature -- in this context, you can't have both.
References
Variadic Functions
Template Specialization
Why do we need virtual functions in C++?
You would have to cast to the derived type first, it is not possible using a base class pointer/reference as the base class will only know about its own implementation. This is not even a case where you can use a recursive dependency on the derived type as the derived type is not defined yet at the point the base is being instantiated.
If you do cast to the derived type then it would be able to resolve the derived member as you desire.
There is no variadic templates in your code like already explained by the others.
But you can use the fact that the templated class methods are instantiated at the first time invoked. But there is no virtual overriding here.
In this example you can define the different implementations of the method templates in Base and Derived classes, but you have explicitely tell the compiler which one to use.
It's not possible to use Derived class method through a Base class pointer without explicit cast:
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base() {};
virtual ~Base() {};
template<typename T>
void ReceiveData(T)
{
throw std::runtime_error("Undefined");
}
};
class Derived : public Base
{
public:
template<typename... Args >
void ReceiveData(Args... args)
{
(void)std::initializer_list<int>{(std::cout << args << std::endl, 0)...};
}
};
int main()
{
Base b;
// b.ReceiveData(1); //-> this calls base class method
Derived d;
d.ReceiveData(1); // this calls the method in the derived class
d.ReceiveData(2, "hello"); // this calls the method in the derived class
Base* b2 = new Derived();
// b2->ReceiveData(3); // this will instantiate and call the base class method
// thus raising an exception
// because no virtual overriding of templated methods
((Derived*)b2)->ReceiveData("world",1); // this will instantiate and call the derived class
// method, then because of explicit casting the
// compiler knows which class to target
return 0;
}
Live demo: https://wandbox.org/permlink/K0qEAC7C7yzg6gYL

Abstract base class using template argument from derived class

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.

Can I use CRTP with multiple derived classes, and use them polymorphically?

I have such hierarchy of classes:
template <class Type>
class CrtpBase
{
protected:
Type& real_this()
{
return static_cast<Type&>(*this);
}
};
template <class ChildType>
class Base : CrtpBase<ChildType>
{
public:
void foo()
{
this->real_this().boo();
}
};
class Derived1 : public Base<Derived1>
{
public:
void boo { ... }
};
class Derived2 : public Base<Derived2>
{
public:
void boo { ... }
};
The thing is, I want to use my classes in this way:
std::vector<Base*> base_vec;
base_vec.push_bach(new Derived1());
base_vec.push_bach(new Derived2());
.........
base_vec[0]->foo();
But this isn't possible, because base class for all derived classes is different (actually Base isn't a type at all, it's template). So, is there a way to use crtp with multiple derived classes, alongside with polymorphism?
Indeed there is, you need to add the appropriate non-template base class too:
class AbstractBase
{
public:
virtual ~AbstractBase() {}
virtual void foo() = 0;
};
template <class ChildType>
class Base : CrtpBase<ChildType>, public AbstactBase
{
void foo() override { this->real_this().boo(); }
};
Then, declare your vector as std::vector<AbstractBase*>.
This does indeed introduce the overhead of dynamic dispatch (which you were probably trying to avoid by using CRTP), but dynamic dispatch is the only way to get runtime polymorphism in C++.
It can still be beneficial, though. For example, if the implementation of foo is shared by all the derived classes, but calls into many different boo-style functions (with each derived class having a different implementation of those), you will only pay the dynamic dispatch cost once when invoking foo, and then all the calls made within foo are dispatched statically, CRTP-style.
On the other hand, if it's just one call to a boo-like function within foo, you may as well make boo virtual, put non-virtual foo into the base, thus getting rid of CRTP. The cost will be the same then: a non-virtual dispatch (foo) and a virtual one (boo).
Side note, you should strongly consider storing smart pointers in the std::vector; owning raw pointers are bad practice.

can i pass object class that is inherited from template class?

How can i pass object that inherited from template as this to function
please see the GameObj::GameObj constructor
i try to pass the GameObj that is inheriting the BaseGameObject template
but its not valid
template<typename T>
class BaseGameObject
{
public:
BaseGameObject(){};
virtual ~BaseGameObject(){};
static T* create(IImageComponent* imageComponent)
{
}
protected:
IImageComponent* m_IImageComponent;
};
class GameObj :public BaseGameObject<GameObj>
{
public:
GameObj(IImageComponent* imageComponent);
virtual ~GameObj(){};
};
GameObj::GameObj(IImageComponent* imageComponent):m_IImageComponent(imageComponent)
{
m_IImageComponent->update(*this); //HERE IS THE PROBLEM IT ASK ME TO PASS TAMPLATE
}
class GameObjImageCompnent
{
public :
GameObjImageCompnent(const std::string &spritefilename);
virtual void update(BaseGameObject& baseGameObject);
private:
std::string m_spritefilename;
};
GameObjImageCompnent::GameObjImageCompnent(const std::string &spritefilename):
m_spritefilename(spritefilename)
{
;
}
void GameObjImageCompnent::update(BaseGameObject& baseGameObject)
{
baseGameObject.setInitWithSpriteFrameName(m_spritefilename);
}
this link doesn't work for me :
Passing template classes as arguments to methods
BaseGameObject is a template. GameObjImageCompnent::update has a declaration virtual void update(BaseGameObject& baseGameObject);. That's wrong because BaseGameObject is not a type but a template.
Maybe you should change that declaration to: virtual void update(BaseGameObject<GameObj>& baseGameObject);
If you need to be able to call that with different BaseGameObjects, you could make GameObjImageCompnent into a template as well:
template<class T>
class GameObjImageCompnent {
// ...
virtual void update(BaseGameObject<T>& baseGameObject);
If that's not an option, you probably need to inherit BaseGameObject from a non-template base class and and use that as your reference type. If a base class for BaseGameObject is not an option either, you need to rethink your design.
class IGameObject {
public:
virtual ~IGameObject() {}
// any other virtual functions that are needed
};
template<typename T>
class BaseGameObject: public IGameObject {
//...
class GameObjImageCompnent {
// ...
virtual void update(IGameObject& baseGameObject);
You seem to be using CRTP. See the pitfalls section:
One issue with static polymorphism is that without using a general base class like "Shape" from the above example, you cannot store your derived classes heterogeneously as each CRTP base class is a unique type. For this reason, it's likely that you'll want to inherit from a shared base class with a virtual destructor, like the example above.
I think that limitation also applies to passing objects of derived classes to a function through a heterogeneous reference.