I created a Foo class which needs to be used only as a shared pointer, so I made the constructor private to prevent client to use Foo directly:
#include <memory>
class Foo {
public:
static std::shared_ptr<Foo> Create() {
return std::shared_ptr<Foo>(new Foo());
}
std::shared_ptr<Foo> Copy() {
return std::shared_ptr<Foo>(new Foo(*this));
}
private:
Foo() = default;
};
I then updated Foo to use the CRTP pattern so I could have a class Bar inherit from it without having to re-define the Create() and Copy() methods:
#include <memory>
template <class Self>
class Foo {
public:
template <class... Args>
static std::shared_ptr<Self> Create(Args&&... args) {
return std::shared_ptr<Self>(new Self(std::forward<Args>(args)...));
}
virtual std::shared_ptr<Self> Copy() {
return std::shared_ptr<Self>(new Self(*this));
}
private:
Foo() = default;
};
class Bar : public Foo<Bar> {};
Then I needed to provide a non-templated FooBase interface that would provide some functions shared by all derived classes:
#include <memory>
class FooBase {
public:
virtual void DoSomething() =0;
};
template <class Self>
class Foo : public FooBase {
public:
template <class... Args>
static std::shared_ptr<Self> Create(Args&&... args) {
return std::shared_ptr<Self>(new Self(std::forward<Args>(args)...));
}
virtual std::shared_ptr<Self> Copy() {
return std::shared_ptr<Self>(new Self(*this));
}
virtual void DoSomething() override { }
private:
Foo() = default;
};
class Bar : public Foo<Bar> {
public:
virtual void DoSomething() override { }
};
Now I also need to expose the Copy() method to the Foobar interface, but I cannot find any elegant ways to do it without changing the name for the interface (e.g. CopyBase())
#include <memory>
class FooBase {
public:
virtual void DoSomething() =0;
// Expose Copy method by using a different name.
virtual std::shared_ptr<FooBase> CopyBase() const =0;
};
template <class Self>
class Foo : public FooBase {
public:
template <class... Args>
static std::shared_ptr<Self> Create(Args&&... args) {
return std::shared_ptr<Self>(new Self(std::forward<Args>(args)...));
}
virtual std::shared_ptr<FooBase> CopyBase() const override {
return Copy();
}
virtual std::shared_ptr<Self> Copy() {
return std::shared_ptr<Self>(new Self(*this));
}
virtual void DoSomething() override { }
private:
Foo() = default;
};
class Bar : public Foo<Bar> {
public:
virtual void DoSomething() override { }
};
This code works, but I feel that there must be a better way to do this. I exposed my thinking process in details as I suspect that the flaws might be in the design, so I'm wondering if anyone could help me gain a different perspective on this issue.
Thanks for your time!
covariant return type is only possible with regular pointer or reference, not with smart pointer.
Additional issue with CRTP is that class is incomplete, so covariance cannot be used neither.
The traditional way is indeed to split the clone in 2 part, a virtual one (private) and a public (non-virtual) one, something like:
template <typename Derived, typename Base>
class Clonable : public Base
{
public:
template <class... Args>
static std::shared_ptr<Derived> Create(Args&&... args) {
return std::shared_ptr<Derived>(new Derived(std::forward<Args>(args)...));
}
std::shared_ptr<Derived> Clone() const {
return std::shared_ptr<Derived>(static_cast<Derived*>(vclone()));
}
private:
// Cannot use covariant-type `Derived*` in CRTP as Derived is not complete yet
Base* vclone() const override {
return new Derived(static_cast<const Derived&>(*this));
}
};
And then
class FooBase {
public:
virtual ~FooBase() = default;
virtual void DoSomething() = 0;
// Expose Copy method by using a different name.
std::shared_ptr<FooBase> Clone() const { return std::shared_ptr<FooBase>(vclone()); }
private:
virtual FooBase* vclone() const = 0;
};
class Bar : public Clonable<Bar, FooBase> {
public:
void DoSomething() override { }
};
Demo
Related
I have the following situation, where I want to instantiate an object of a template type.
I want the instantiation of the template type object to depend on the "instantiator" class.
template <class T>
class Base
{
public:
Base(){}
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test()
{
return T(5);
}
};
template <class T>
class Derived : public Base<T>
{
public:
Derived() : Base<T>() {}
virtual T Test()
{
return T(5, 6);
}
};
class Test1
{
public:
Test1(int x){}
};
class Test2 : public Test1
{
public:
Test2(int x, int y) : Test1(x) {}
};
Later in my code I want to work with Base or Derived objects.
They perform operations on a template type object (obj) in function do_something().
I want to let the instantiation of obj depend on the implementation
of the Test() function.
Base should only work with objects of type Test1 or derived classes of Test1 that have the same constructor.
Derived should only work on objects that have the same constructor as Test2.
Base<Test1>(); // works
Base<Test2>(); // doesn't work, but should not work by my design and throw a compile error
Derived<Test1>(); // same
Derived<Test2>(); // should work, but doesn't,
// since Base::Test() still exists, but cannot be compiled due to wrong constructor of T
Is there a way to implement the described behavior?
Or is there a design change I can make?
You might change Base to be correct for any T:
template <class T>
class Base
{
public:
Base(){}
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test()
{
if constexpr (std::is_constructible_v<T, int>) {
return T(5);
}
throw std::runtime_error("should not be called");
}
};
but
Base<Test2>(); would compile but throw at runtime.
Seems better to split and have two derived:
template <class T>
class Base
{
public:
Base() = default;
virtual ~Base() = default;
void do_something()
{
T obj = this->Test();
// do something with object
}
virtual T Test() = 0;
};
template <class T>
class Derived : public Base<T>
{
public:
Derived() : Base<T>() {}
T Test() override { return T(4); }
};
template <class T>
class Derived2 : public Base<T>
{
public:
Derived() : Base<T>() {}
T Test() override { return T(5, 6); }
};
I got three classes. One ClassFactoryBase which looks like this:
class ClassFactoryBase {
public:
virtual ~ClassFactoryBase () = default;
virtual AbstractBase* Create() = 0;
};
I inherit from that class the actual Factory as a template
template <typename Type>
class ClassFactory final : public ClassFactoryBase {
ClassFactory (/*ClassFactoryBase& Factory*/); //Idea to automatically add them
~ClassFactory () = default;
AbstractBase* Create() override; //returns new Type
};
And ofc I implemented the Factory itself:
class ClassTypeFactory {
public:
template<typename Type>
void AddFactory(ClassFactoryBase& ClassFactory); // inserts ClassFactory into the map m_Factories
AbstractBase* Create(const std::string& ClassType);
private:
std::map<std::string, ClassFactoryBase&> m_Factories;
};
If I implement it like this I have to add to this Inside of my main.cpp
ClassTypeFactory class_type_factory;
ClassFactory<TopClass> top_state_factory(&class_type_factory);
class_type_factory.AddFactory<TopClass>(top_class_factory); // leave this out
This works just fine but I wonder if I could implement it in a way that I can leave out the last line. I think it should work because they both use the same template parameter.
I tried to give my ClassFactory a reference to a Factory and than call the AddFactory Method in there but I cant make it work. I always get inaccessible errors.
You just have to do it in correct order. Following modified version of your example (using smart pointer):
// Your objects to create:
struct AbstractBase
{
virtual ~AbstractBase () = default;
// ...
};
struct Derived : AbstractBase
{
// ...
};
// Your abstract factory
class ClassFactoryBase {
public:
virtual ~ClassFactoryBase () = default;
virtual std::unique_ptr<AbstractBase> Create() = 0;
};
// Your factory collection
class ClassTypeFactory {
public:
void AddFactory(const std::string& name, ClassFactoryBase& factory) { m_Factories.emplace(name, std::ref(factory)); }
std::unique_ptr<AbstractBase> Create(const std::string& name)
{
return m_Factories.at(name).get().Create();
}
private:
std::map<std::string, std::reference_wrapper<ClassFactoryBase>> m_Factories;
};
// Your real factory
template <typename Type>
class ClassFactory final : public ClassFactoryBase {
public:
ClassFactory(const std::string& name, ClassTypeFactory& factory) { factory.AddFactory(name, *this); }
std::unique_ptr<AbstractBase> Create() override { return std::make_unique<Type>(); }
};
And then usage:
ClassTypeFactory class_type_factory;
ClassFactory<Derived> top_state_factory("TopClass", class_type_factory);
auto ptr = class_type_factory.Create("TopClass");
Demo
I am using a composite design pattern and I want to clone my objects from my composite class. I tried to make a generic clone method in my component class, but when I try to send the concrete type of my object to the generic (template) method, 'typeof' and 'typeid' returns the abstract class type. So, when I try to use new typeof(object), I see the error
"invalid new-expression of abstract class type 'Component'".
My compiler is MigGW 32 bits.
As I can't know the type of my object, I can't use dynamic_cast.
Am I using typeof/typeid wrongly or should I use other keyword to know the concrete object type?
#include <iostream>
#include <vector>
#include <typeinfo>
class Component
{
public:
template <typename Tdest> typename std::remove_cv<typename std::remove_pointer<Tdest>::type>::type* clone() const
{
typedef typename std::remove_cv<typename std::remove_pointer<Tdest>::type>::type NO_POINTER_NOR_CV;
return new typeof(NO_POINTER_NOR_CV)(*dynamic_cast<const NO_POINTER_NOR_CV*>(this));
}
virtual void manipulateComponents() = 0;
virtual void add(Component* comp) = 0;
protected:
std::vector<const Component*> _v;
};
class Leaf : public Component
{
void manipulateComponents() override { return; }
void add(Component* comp) override { return; }
};
class Composite : public Component
{
public:
void manipulateComponents() override
{
for(auto component : _v)
{
std::cout << typeid(component).name() << std::endl; // print PK9Component
component->clone<typeof(component)>();
/* ... */
}
}
void add(Component* comp) override { _v.push_back(comp); }
};
int main(int argc, char* argv[])
{
Component* l = new Leaf();
Component* c = new Composite();
Component* parent = new Composite();
parent->add(l);
parent->add(c);
parent->manipulateComponents();
}
You are not getting the details of the derived type using typeid since you are using it on a pointer. Dereference the pionter in the call to get the name of the derived type.
Change
std::cout << typeid(component).name() << std::endl; // print PK9Component
// PK9Component seems indicate that it is a pointer to a Component.
to
std::cout << typeid(*component).name() << std::endl;
// ^^
If you want a clone method, you have to add a virtual function to return it, as in:
struct A
{
virtual std::unique_ptr<A> clone() const = 0;
A() = default;
A(A const&) = default;
A(A&&) = default;
A& operator=(A&&) = default;
A& operator=(A const&) = default;
virtual ~A() = default;
};
struct B : A
{
std::unique_ptr<A> clone() const override
{
assert(typeid(*this) == typeid(B));
return std::make_unique<B>(*this);
}
};
The assert protects (at run time) against deriving from B w/o overriding the clone() method.
The C++ Committee is working on A polymorphic value-type for C++, but that won't be available for a while.
No amount of typeof magic in your clone method will give you the type of a subclass of a non-templated class. It can give you the type of an instantiated template, but the only possible instantiation of your clone method here is in your base class. Subclassing doesn't redefine template methods.
If you really want to, you can use template methods in subclassing if you're willing to use the "Curiously Recurring Template Pattern". There's a sample clone implementation on Wikipedia, which I'll quote here:
// Base class has a pure virtual function for cloning
class Shape {
public:
virtual ~Shape() {};
virtual Shape *clone() const = 0;
};
// This CRTP class implements clone() for Derived
template <typename Derived>
class Shape_CRTP : public Shape {
public:
virtual Shape *clone() const {
return new Derived(static_cast<Derived const&>(*this));
}
};
// Nice macro which ensures correct CRTP usage
#define Derive_Shape_CRTP(Type) class Type: public Shape_CRTP<Type>
// Every derived class inherits from Shape_CRTP instead of Shape
Derive_Shape_CRTP(Square) {};
Derive_Shape_CRTP(Circle) {};
With CRTP, you may do:
template <typename Derived>
class IClonable
{
public:
virtual ~IClonable() = default;
std::unique_ptr<Derived> clone() const {
return std::unique_ptr<Derived>(cloneImpl());
}
protected:
virtual Derived* cloneImpl() const = 0;
};
template <typename Derived, typename Base>
class Clonable : public Base
{
public:
std::unique_ptr<Derived> clone() const { // Hide Base::clone to return static type.
return std::unique_ptr<Derived>(static_cast<Derived*>(cloneImpl()));
}
protected:
Clonable* cloneImpl() const { return new Derived{static_cast<const Derived&>(*this)}; }
};
And then:
class Component : public IClonable<Component>
{
public:
virtual void manipulateComponents() = 0;
virtual void add(const Component&) = 0;
};
class Leaf : public Clonable<Leaf, Component>
{
public:
void manipulateComponents() override {}
void add(const Component&) override {}
};
class Composite : public Clonable<Composite, Component>
{
public:
void manipulateComponents() override
{
for (const auto* component : _v)
{
auto cloned = component->clone(); // std::unique_ptr<Component>
/* ... */
}
}
void add(const Component& comp) override { _v.push_back(&comp); }
protected:
std::vector<const Component*> _v;
};
With possible usage:
Leaf l;
Composite c;
auto parent = c.clone(); // std::unique_ptr<Composite>
parent->add(l);
parent->add(c);
parent->manipulateComponents();
How can you switch between multiple sets of static methods where each set is required to have the same signature? The natural way seemed to implement a common interface, but there is no virtual static method in C++.
You can lift the static property to a single instance and use a template:
template<typename Derived>
class StaticInterface {
protected:
StaticInterface() {}
public:
virtual ~StaticInterface() {}
static Derived& instance() {
Derived theInstance;
return theInstance;
}
// The interface:
virtual void foo() = 0;
virtual void bar() = 0;
};
And use that like
class DervivedA : public StaticInterface<DerivedA> {
template<typename Derived>
friend class StaticInterface<Derived>;
DerivedA() {}
public:
virtual void foo() {};
virtual void bar() {};
};
class DervivedB : public StaticInterface<DerivedB> {
template<typename Derived>
friend class StaticInterface<Derived>;
DerivedB() {}
public:
virtual void foo() {};
virtual void bar() {};
};
Or omit the virtual part (and creation of a "costly" vtable) completely:
template<typename Derived>
class StaticInterface {
protected:
StaticInterface() {}
public:
~StaticInterface() {}
static Derived& instance() {
Derived theInstance;
return theInstance;
}
// The interface:
void foo() {
Derived::foo_impl();
}
void bar() {
Derived::bar_impl();
}
};
class DervivedA : public StaticInterface<DerivedA> {
template<typename Derived>
friend class StaticInterface<Derived>;
DerivedA() {}
public:
void foo_impl() {};
void bar_impl() {};
};
I have simple base and derived class that I want both have shared_from_this().
This simple solution:
class foo : public enable_shared_from_this<foo> {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&foo::foo_do_it,shared_from_this());
}
virtual ~foo() {};
};
class bar1 : public foo , public enable_shared_from_this<bar1> {
using enable_shared_from_this<bar1>::shared_from_this;
void bar1_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar1::bar1_do_it,shared_from_this());
}
};
Causes exception tr1::bad_weak_ptr in following code:
shared_ptr<foo> ptr(shared_ptr<foo>(new bar1));
function<void()> f=ptr->get_callback();
f();
So after "googling" I have found following solution:
class bar2 : public foo {
void bar2_do_it()
{
cout<<"foo::do_it\n";
}
shared_ptr<bar2> shared_from_this()
{
return boost::static_pointer_cast<bar2>(foo::shared_from_this());
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar2::bar2_do_it,shared_from_this());
}
};
And now it works.
Is there any better and more convinient and correct way to enable_shared_from_this for both parent and child?
Thanks
The OP solution can be made more convenient by defining the following on the base class.
protected:
template <typename Derived>
std::shared_ptr<Derived> shared_from_base()
{
return std::static_pointer_cast<Derived>(shared_from_this());
}
This can be made more convenient by placing it in a base class (for reuse).
#include <memory>
template <class Base>
class enable_shared_from_base
: public std::enable_shared_from_this<Base>
{
protected:
template <class Derived>
std::shared_ptr<Derived> shared_from_base()
{
return std::static_pointer_cast<Derived>(shared_from_this());
}
};
and then deriving from it as follows.
#include <functional>
#include <iostream>
class foo : public enable_shared_from_base<foo> {
void foo_do_it()
{
std::cout << "foo::do_it\n";
}
public:
virtual std::function<void()> get_callback()
{
return std::bind(&foo::foo_do_it, shared_from_base<foo>());
}
};
class bar1 : public foo {
void bar1_do_it()
{
std::cout << "bar1::do_it\n";
}
public:
virtual std::function<void()> get_callback() override
{
return std::bind(&bar1::bar1_do_it, shared_from_base<bar1>());
}
};
Sorry, but there isn't.
The problem is that shared_ptr<foo> and shared_ptr<bar1> are different types. I don't understand everything that's going on under the hood, but I think that when the constructor returns and is assigned to a shared_ptr<foo>, the internal weak_ptr<bar1> sees that nothing is pointing to it (because only a shared_ptr<bar1> would increment the counter) and resets itself. When you call bar1::shared_from_this in get_callback, you get the exception because the internal weak_ptr isn't pointing to anything.
Essentially, enable_shared_from_this only seems to work transparently from a single class in a hierarchy. If you try implementing it manually, the problem should become obvious.
A similar solution to #evoskuil that reduces boilerplate in derived classes should you want to implement a shared_from_this() function, resulting in the following code at the point of use in the class:
auto shared_from_this() {
return shared_from(this);
}
This uses 'shim' functions outside of the class. By doing it that way it also provides a clean way to do this for classes who's interface can't be modified but derive from enable_shared_from_this - e.g.
auto shared_that = shared_from(that);
Note: Use of auto for return types here will depend upon the age of your compiler.
Shim functions that could be placed in a library header:
template <typename Base>
inline std::shared_ptr<Base>
shared_from_base(std::enable_shared_from_this<Base>* base)
{
return base->shared_from_this();
}
template <typename Base>
inline std::shared_ptr<const Base>
shared_from_base(std::enable_shared_from_this<Base> const* base)
{
return base->shared_from_this();
}
template <typename That>
inline std::shared_ptr<That>
shared_from(That* that)
{
return std::static_pointer_cast<That>(shared_from_base(that));
}
The above code relies on the fact that the type passed to shared_from(...) inherits from std::enable_shared_from_this<Base> at some point in its ancestry.
Calling shared_from_base will figure out what type that ultimately was. Since we know that That inherits from Base, a static downcast can be made.
Probably there are some pathological corner cases with classes having type conversion operators.. but that's unlikely to occur in code not designed to break this.
Example:
struct base : public std::enable_shared_from_this<base> {};
struct derived : public base
{
auto shared_from_this() {
return shared_from(this);
}
// Can also provide a version for const:
auto shared_from_this() const {
return shared_from(this);
}
// Note that it is also possible to use shared_from(...) from
// outside the class, e.g.
// auto sp = shared_from(that);
};
template <typename X>
struct derived_x : public derived
{
auto shared_from_this() {
return shared_from(this);
}
};
Compilation test:
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
auto const& const_pderived = *pderived;
const_pderived.shared_from_this();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
https://onlinegdb.com/SJWM5CYIG
Prior solution that I posted, kept to make the comments still make sense - this placed the functions in the base class which had some problems - particularly non-uniformity between the required implementation for 'normal' classes and template classes.
Additionally the implementation in the base class would need to be repeated for new class hierarchies which is not all that DRY.
Furthermore the base class function suffered from the possibility of misuse by supplying a base class pointer from a different object. The newer scheme above avoids this entirely and the runtime assert(...) check goes.
Old implementation:
#include <cassert>
#include <memory>
class base : public std::enable_shared_from_this<base>
{
protected:
template <typename T>
std::shared_ptr<T> shared_from(T* derived) {
assert(this == derived);
return std::static_pointer_cast<T>(shared_from_this());
}
};
class derived : public base
{
public:
auto shared_from_this() {
return shared_from(this);
}
};
template <typename X>
class derived_x : public derived
{
public:
auto shared_from_this() {
return this->template shared_from(this);
}
};
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
Quite easy; inherit public shared_from_this only in your base class. Implement an accessor in your derived class that casts to the appropriate type;
std::shared_ptr<Derived> shared()
{
return std::dynamic_pointer_cast<Derived>(Base::shared_from_this());
}
With c++23 deducing this, things become much easier. https://godbolt.org/z/j499WK58Y
#include <memory>
#include <iostream>
#include <functional>
using namespace std;
struct new_enable_shared_from_this :
public std::enable_shared_from_this<new_enable_shared_from_this> {
template <typename Self>
auto new_shared_from_this(this Self& self) {
return std::static_pointer_cast<Self>(self.shared_from_this());
}
};
class foo : public new_enable_shared_from_this {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return bind(&foo::foo_do_it,new_shared_from_this());
}
virtual ~foo() {};
};
class bar1 : public foo {
void bar1_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return bind(&bar1::bar1_do_it,new_shared_from_this());
}
};
int main() {
auto pf = std::make_shared<foo>();
pf->get_callback()();
auto pb = std::make_shared<bar1>();
pb->get_callback()();
}
This is the previous answer:
Well, I don't like virtual function. Virtual function is just for type erasing, but we don't need type erasing all the time. So, provide a mechanism for type erasing is enough. Here is an example that don't use virtual function:
#include <iostream>
#include <functional>
#include <memory>
using namespace std;
template<typename derived>
class foo_imp {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
function<void()> get_callback()
{
auto&& d = static_cast<derived&>(*this);
return bind(&foo_imp::foo_do_it, d.shared_from_this());
}
};
template<typename derived>
class bar_imp {
void bar_do_it()
{
cout<<"bar::do_it\n";
}
public:
function<void()> get_callback()
{
auto&& d = static_cast<derived&>(*this);
return bind(&bar_imp::bar_do_it, d.shared_from_this());
}
};
struct foo : public foo_imp<foo>, public enable_shared_from_this<foo> {};
struct bar : public bar_imp<bar>, public enable_shared_from_this<bar> {};
struct v_foo {
virtual function<void()> get_callback() = 0;
};
template <typename T>
std::shared_ptr<v_foo> convert(const std::shared_ptr<T>& st) {
struct _ : public v_foo {
_(const std::shared_ptr<T>& st) : _st{st} {}
function<void()> get_callback() override {
return _st->get_callback();
}
std::shared_ptr<T> _st;
};
return std::make_shared<_>(st);
}
int main() {
auto sf = make_shared<bar>();
sf->get_callback()();
auto svf = convert(sf);
svf->get_callback()();
auto sb = make_shared<foo>();
sb->get_callback()();
auto svb = convert(sb);
svb->get_callback()();
}
#include <memory>
template<class T>
class Base : public std::enable_shared_from_this<T> {
};
class Derived : public Base<Derived> {
std::shared_ptr<Derived> getDerived() { return shared_from_this(); }
};