Creating objects only as shared pointers through a base class 'create'-method - c++

I am trying to achieve that certain objects within my application can only be constructed as shared_ptr's by a call to a static method called "create".
Of course I could do this by directly adding the static 'create' method to all the respective class. However, this would mean I have to repeat very similar code in almost all my classes. A macro would work, but I do not find this very elegant.
I came up with an alternative way of doing this by deriving all classes from a templated 'BaseObject' class that implements the 'create' method and returns the pointer. This almost works, except that std::make_shared cannot access the constructor of its child class when it is protected.
The non-solution would be to make the child class constructor public (see (1) in the example below). But now Foo can be normally constructed again and this would defeat the entire point. An alternative solution would be to friend BaseObject in the child class and make use of shared_ptr directly (see (2) in the example).
Both solutions put extra burden on the implementer of the child class. Since they have to either find an alternative way of making the constructor non-public or put a friend declaration. The (2) solution has the additional problem of not being able to use the more efficient make_shared.
My question: is there a better way of doing this?
template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(args...);
//return std::shared_ptr<T>(new T(args...)); (2)
}
};
class Foo : public BaseObject<Foo>
{
//friend BaseObject<Foo>; (2)
protected: //public (1)
Foo(int a = 0) : m_foo(a) {}
private:
int m_foo;
};
int main(int argc, char* argv[])
{
Foo::SharedPtr bla = Foo::create(1);
return 0;
}
Update:
They pass-key idiom seems to provide the best solution for me at this moment:
template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
class Key
{
friend class BaseObject<T>;
Key() {}
};
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(Key(), args...);
}
};
class Foo : public BaseObject<Foo>
{
public:
Foo(BaseObject<Foo>::Key, int a = 0) : m_foo(a) {}
private:
int m_foo;
};
The good things:
Only possible to create an object of Foo as a shared_ptr through
Foo::create.
No need to add complex friend declarations in Foo.
std::make_shared still works.
The only problem with this solution is the requirement to have 'Key' as a first argument in the constructor. But I can live with that.

Better is subjective, but I believe it would be a little more intuitive if you would make your constructor private, and std::make_shared a friend function. This way the only function that could create your object would be std::make_shared, and you could write
std::shared_ptr<Foo> ptr = std::make_shared<Foo>(12);
instead of:
Foo::SharedPtr bla = Foo::create(1);
So any future reader of your code would understand what you mean withou actually looking at the Foo class.
UPDATE
I have tried out what I wrote, but did not really work. Here is an answer for a similar question instead, which most likely also aplies for your question:
Using make_shared with a protected constructor + abstract interface
UPDATE 2
Here is how you can make it work (VC++2013)
#include <memory>
using namespace std;
class Foo
{
protected:
Foo(int a = 0) : m_foo(a) {}
private:
int m_foo;
friend shared_ptr<Foo> make_shared<>();
friend class _Ref_count_obj<Foo>;
};
int main()
{
shared_ptr<Foo> foo = make_shared<Foo, int>(12);
return 0;
}
_Ref_count_obj is internally used by make_shared, that's why you need to befriend that too.

Related

How to handle classes which "own" other classes

I want to make a base class which handles the construction of sub-classes. A sub-class then wants to call a function from the base class so I am passing it a pointer to be able to achieve this. The base class then passes back the sub-class to the user.
Is the below method an acceptable strategy for this? And is it safe to pass back an object in this fashion? If not, what would be a better alternative? I am concerned this becomes messy quickly as each subclass needs to be a friend for the base and it generally seems a bit clunky.
class SubClass
{
private:
SubClass(MyClass* parent) {
...
parent->DoStuff();
...
}
}
class MyClass
{
public:
SubClass CreateSubClass() {
return SubClass(this);
}
private:
void DoStuff() {
...
}
friend class SubClass;
}
MyClass a;
SubClass b = a.CreateSubClass();
Thanks in advance!
Nothing is really wrong with your code pattern. As super already mentioned in a comment, I'd probably pass a MyClass& reference instead of a MyClass* pointer.
If you want to reduce the class interdependencies and remove the need for friendship, you might pass a functor instead of the MyClass:
class SubClass
{
public:
template <class F>
explicit SubClass(F stuff_doer) {
...
stuff_doer();
...
}
};
class MyClass
{
public:
SubClass CreateSubClass() {
return SubClass([this] { DoStuff(); });
}
private:
void DoStuff();
};
Or if you don't want or can't have the SubClass constructor defined in a header file, instead of a constructor template you could use a std::function functor to erase the functor type:
class SubClass
{
public:
explicit SubClass(std::function<void()> stuff_doer);
};

C++: Override method which has the same name as the class

Let's say I have a nice looking base class called base:
class base
{
public:
virtual void foo() const = 0;
};
Now, I have a class named foo that I would like to inherit from base and override base::foo:
class foo : public base
{
public:
virtual void foo() const override;
};
This is illegal in C++, as you are not allowed to name a method the same thing as the class (C++ greedily believes methods with the same name as the class are constructors, which are not allowed to have return types). Is there any way around this that doesn't involve changing the name of the class or method? I want external users to be able to create foo classes without the knowledge that there is a method base::foo called by someone else (imagine foo can be both a noun and a verb).
Is there any way around this that doesn't involve changing the name of the class or method?
No, there isn't.
All methods named foo are special in class foo -- they are constructors. Hence, they cannot be overridden virtual member functions.
I'll take a wild guess and just say NO.
You can have a lot of ambiguities in C++ (that sometimes have to be explicitly disambiguated), but I don't even see a way how a compiler or programmer could disambiguate this situation. Well, A programmer can (a function with a return type is obviously not a constructor), but C++ can't.
In C++, the only method that can have the class' name is its constructor.
So, no. You can't.
Okay, here's my (slightly evil) solution...
// Create an intermediate class which actually implements the foo method:
class foo_intermediate : public base
{
public:
virtual void foo() const override;
};
// Derive from that class and forward the constructor along
class foo : public foo_intermediate
{
public:
using foo_intermediate::foo_intermediate;
private:
friend class foo_intermediate;
// Actual implementation for the foo function goes here
void foo_impl() const;
};
// In some CPP file:
void foo_intermediate::foo() const
{
// Need to access the typename foo via namespace (global here)
static_cast<const ::foo*>(this)->foo_impl();
}
Actually calling foo is a bit funny, since this can't work:
void bar()
{
foo x;
x.foo(); // <- illegal attempt to access to the foo constructor
}
You must access through an alias:
void baz()
{
foo x;
base& rx = x;
rx.foo(); // legal
}
As an alternative, you can use a typedef:
class foo_impl : public base
{
public:
virtual void foo() const override;
};
using foo = foo_impl;
This gets around the issue of calling x.foo(), since it no longer appears as a constructor access.
I made a Gist so others could play with the two solutions if they are so inclined.

Make sure only Smartpointers are build

I want to make sure only smart pointers are build from my classes so i made all constructors protected.
To create objects i build this "Buildable"-Policy:
template <typename T>
class Buildable
{
public:
template<typename ...Args>
static QSharedPointer<T> buildObject(Args&&... all)
{
return QSharedPointer<T>( new T(std::forward<Args>(all)...) );
}
};
If i use this this policy in a base class, all goes well.
But when i use it in base and a derived class like this:
class A : public Buildable<A> {}
class B : A, public Buildable<B>{}
the compiler argues: Error: member 'buildObject' found in multiple base classes of different types
I don't know how to solve this problem. Any ideas?
Cause of the error
This is because the multiple inheritance here:
class B : A, public Buildable<B>{};
It causes class B to inherit from Buildable<A> and from Buildable<B> which both contain a buildObject() overload. Unfortunately, both overloads differs only by the return type. This is not allowed.
Design issue
Unfortunately, you can't avoid this unless you could smuggle an additional parameter to buildObject(), which could permit the compiler to use proper type derivation to resolve avoid ambiguity.
But do you really intend to have multiple inheritance in your design here ? If your classes would be polymorphic, couldn't you use a class B defined as follows:
class B : public A {}; // inherits from Buildable A
...
QSharedPointer<A> b = B::buildObject(); //
Alternative design
The alternative could be to put the building class at the bottom of the derivation, to avoid the conflicts. Make your constructors for classes A and B protected, and use this template class :
// (I used here shared_ptr instead of QSharedPointer for testing purpose)
template <typename T>
class Builder : public T
{
public:
Builder() = delete;
Builder (const Builder&) = delete;
template<typename ...Args>
static shared_ptr<T> buildObject(Args&&... all)
{
return make_shared<T>(std::forward<Args>(all)...) ;
}
};
class A { };
class B : public A {}; // Normal class hierarchy.
// can't be instantiated if ctor are protected.
shared_ptr<A> a = Builder<A>::buildObject();
shared_ptr<B> b = Builder<B>::buildObject();
One easy solution to the design problem is to make buildObject a freestanding function template, that you make a friend of each user class.
In order to simplify friend declarations you may want to put that function template in a class.
Then it's very much like your existing code, except there's no inheritance from the factory class:
#include <memory> // std::shared_ptr
#include <utility> // std::forward
namespace my{
using std::forward;
using std::shared_ptr;
template< class Class >
struct Make_
{
template< class... Args >
static auto instance( Args&&... args )
-> shared_ptr<Class>
{ return shared_ptr<Class>( new Class( forward<Args>( args )... ) ); }
};
class A
{
template< class > friend struct Make_;
protected:
A( int ) {}
};
class B
: public A
{
template< class > friend struct Make_;
protected:
B( int x ): A( x ) {}
};
} // namespace my
auto main() -> int
{
using namespace my;
auto p = Make_<B>::instance( 42 );
}
General solutions to the immediate technical problem of providing a covariant function without repeating its definition, include:
A macro (that expands to the function definition).
This is what I recommend, if you feel that it absolutely has to be a member function. It's one of the few legitimate uses of macros.
Middle-man inheritance.
Essentially instead of inheriting directly from a Base and also from a mixin, you inherit from the mixin and ask it to inherit from Base. You need to forward constructor arguments from the mixin.
Dominance in virtual inheritance hierarchy.
A really ugly and complex solution. Don't go there. But it's a technical possibility.
Finally there is non-solution of using a function that returns a (smart) pointer to base class. Where the client code has to cast it down. It's really ungood in its own way, but I mention it for completeness.
You could inherit from QEnableSharedFromThis (see here for further details).
As an example:
class C: public QEnableSharedFromThis<C> {
C() = default;
// all the other constructors
public:
template<typename ...Args>
static QSharedPointer<C> create(Args&&... all) {
// refers one of the available constructors
return QSharedPointer<C>(new C{std::forward<Args>(all)...});
}
QSharedPointer<C> getSharedFromThis() {
return sharedFromThis();
}
};
You can use it as a base class for your hierarchy.

Function pointer to object constructor [duplicate]

I'm working on implementing a reflection mechanism in C++.
All objects within my code are a subclass of Object(my own generic type) that contain a static member datum of type Class.
class Class{
public:
Class(const std::string &n, Object *(*c)());
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
For any subclass of Object with a static Class member datum, I want to be able to initialize 'create' with a pointer to the constructor of that subclass.
You cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
Your best bet is to have a factory function/method that creates the Object and pass the address of the factory:
class Object;
class Class{
public:
Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
class Object {};
Object* ObjectFactory()
{
return new Object;
}
int main(int argc, char**argv)
{
Class foo( "myFoo", ObjectFactory);
return 0;
}
I encountered this same problem. My solution was a template function which called the constructor.
template<class T> MyClass* create()
{
return new T;
}
To use this as a function pointer is simple:
MyClass* (*createMyClass)(void) = create<MyClass>;
And to get an instance of MyClass:
MyClass* myClass = createMyClass();
Lambda style:
[](){return new YourClass();}
Using variadic templates you can create a wrapper which will turn the constructor into a functor.
#include <utility>
template <typename T>
struct BindConstructor{
template<typename... Args>
T operator()(Args&&...args)const{
return T(std::forward<Args>(args)...);
}
};
struct Foo {
Foo(int a, int b):a(a),b(b){}
int a;
int b;
};
template <typename Fn>
auto Bar(Fn f){
return f(10,20);
}
int main(){
Foo foo = Bar(BindConstructor<Foo>());
}
https://godbolt.org/z/5W383McTc
Hmm, odd. create is a member variable i.e. only available in class instances but the intent of it seems to be creating an instance in the first place.
You cannot take the address of a constructor, but you can create static factory methods of your own and take the address of that.
You can't use regular function pointers on methods, you have to use method pointers, which have bizarre syntax:
void (MyClass::*method_ptr)(int x, int y);
method_ptr = &MyClass::MyMethod;
This gives you a method pointer to MyClass's method - MyMethod. However this isn't a true pointer in that it's not an absolute memory address, it's basically an offset (more complicated than that due to virtual inheritance, but that stuff is implementation specific) into a class. So to use the method pointer, you have to supply it with a class, like this:
MyClass myclass;
myclass.*method_ptr(x, y);
or
MyClass *myclass = new MyClass;
myclass->*method_ptr(x, y);
Of course it should be obvious at this point that you can't use a method pointer to point to an objects constructor. In order to use a method pointer you need to have an instance of the class so it's constructor has already been called! So in your case Michael's Object Factory suggestion is probably the best way of doing it.
Using Qt, you can call a constructor with Qt reflection mechanisms (QMetaObject) if you declare the constructor as Q_INVOKABLE (nothing more to do than that).
class MyClass : public QObject {
Q_OBJECT
public:
Q_INVOKABLE MyClass(int foo);
MyClass *cloningMySelf() {
return metaObject()->newInstance(Q_ARG(int, 42));
}
};
I'm not sure you will want to embed Qt just for that feature ;-) but maybe you would like to have a look on the way it does that.
http://doc.qt.io/qt-5/metaobjects.html#meta-object-system
If you want an actual function pointer representing the constructor, not a functor or closure, you can create a universal factory template:
#include <iostream>
namespace {
template <typename Type, typename... Args>
Type create(Args... args)
{
return Type{std::forward<Args>(args)...};
}
}
template <typename Type, typename... Args>
static constexpr auto constructor = &create<Type, Args...>;
struct Foo {
Foo(double v){ std::cout << "Foo ctor " << v << std::endl; }
};
int main()
{
auto z = constructor<Foo, double>(0.33);
return 0;
}
Foo ctor 0.33
https://godbolt.org/z/qKGGGzjTs
This is similar to Michael Burr's answer, except that you don't have a static factory method per object and it allows any kind of constructor (not just default)
This is similar to bradgonesurfing's answer, except that you create one function pointer per constructor and not one functor per class representing all constructors for that class.
Even though this question is old and already has several very helpful answers, I am adding this additional suggestion because having one function pointer for every constructor of any class is useful when implementing a runtime type reflection system.

How to pass a function pointer that points to constructor?

I'm working on implementing a reflection mechanism in C++.
All objects within my code are a subclass of Object(my own generic type) that contain a static member datum of type Class.
class Class{
public:
Class(const std::string &n, Object *(*c)());
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
For any subclass of Object with a static Class member datum, I want to be able to initialize 'create' with a pointer to the constructor of that subclass.
You cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
Your best bet is to have a factory function/method that creates the Object and pass the address of the factory:
class Object;
class Class{
public:
Class(const std::string &n, Object *(*c)()) : name(n), create(c) {};
protected:
std::string name; // Name for subclass
Object *(*create)(); // Pointer to creation function for subclass
};
class Object {};
Object* ObjectFactory()
{
return new Object;
}
int main(int argc, char**argv)
{
Class foo( "myFoo", ObjectFactory);
return 0;
}
I encountered this same problem. My solution was a template function which called the constructor.
template<class T> MyClass* create()
{
return new T;
}
To use this as a function pointer is simple:
MyClass* (*createMyClass)(void) = create<MyClass>;
And to get an instance of MyClass:
MyClass* myClass = createMyClass();
Lambda style:
[](){return new YourClass();}
Using variadic templates you can create a wrapper which will turn the constructor into a functor.
#include <utility>
template <typename T>
struct BindConstructor{
template<typename... Args>
T operator()(Args&&...args)const{
return T(std::forward<Args>(args)...);
}
};
struct Foo {
Foo(int a, int b):a(a),b(b){}
int a;
int b;
};
template <typename Fn>
auto Bar(Fn f){
return f(10,20);
}
int main(){
Foo foo = Bar(BindConstructor<Foo>());
}
https://godbolt.org/z/5W383McTc
Hmm, odd. create is a member variable i.e. only available in class instances but the intent of it seems to be creating an instance in the first place.
You cannot take the address of a constructor, but you can create static factory methods of your own and take the address of that.
You can't use regular function pointers on methods, you have to use method pointers, which have bizarre syntax:
void (MyClass::*method_ptr)(int x, int y);
method_ptr = &MyClass::MyMethod;
This gives you a method pointer to MyClass's method - MyMethod. However this isn't a true pointer in that it's not an absolute memory address, it's basically an offset (more complicated than that due to virtual inheritance, but that stuff is implementation specific) into a class. So to use the method pointer, you have to supply it with a class, like this:
MyClass myclass;
myclass.*method_ptr(x, y);
or
MyClass *myclass = new MyClass;
myclass->*method_ptr(x, y);
Of course it should be obvious at this point that you can't use a method pointer to point to an objects constructor. In order to use a method pointer you need to have an instance of the class so it's constructor has already been called! So in your case Michael's Object Factory suggestion is probably the best way of doing it.
Using Qt, you can call a constructor with Qt reflection mechanisms (QMetaObject) if you declare the constructor as Q_INVOKABLE (nothing more to do than that).
class MyClass : public QObject {
Q_OBJECT
public:
Q_INVOKABLE MyClass(int foo);
MyClass *cloningMySelf() {
return metaObject()->newInstance(Q_ARG(int, 42));
}
};
I'm not sure you will want to embed Qt just for that feature ;-) but maybe you would like to have a look on the way it does that.
http://doc.qt.io/qt-5/metaobjects.html#meta-object-system
If you want an actual function pointer representing the constructor, not a functor or closure, you can create a universal factory template:
#include <iostream>
namespace {
template <typename Type, typename... Args>
Type create(Args... args)
{
return Type{std::forward<Args>(args)...};
}
}
template <typename Type, typename... Args>
static constexpr auto constructor = &create<Type, Args...>;
struct Foo {
Foo(double v){ std::cout << "Foo ctor " << v << std::endl; }
};
int main()
{
auto z = constructor<Foo, double>(0.33);
return 0;
}
Foo ctor 0.33
https://godbolt.org/z/qKGGGzjTs
This is similar to Michael Burr's answer, except that you don't have a static factory method per object and it allows any kind of constructor (not just default)
This is similar to bradgonesurfing's answer, except that you create one function pointer per constructor and not one functor per class representing all constructors for that class.
Even though this question is old and already has several very helpful answers, I am adding this additional suggestion because having one function pointer for every constructor of any class is useful when implementing a runtime type reflection system.