I have some third-party abstract base class
struct foo
{
virtual foo*job() = 0;
...
static void* make_space(size_t sizeofDerived);
};
which I cannot alter. Objects of type foo (and all derived classes) must only be created/constructed using placement-new into the memory returned by foo::make_space(),
because ordinary construction, as in
derived_from_foo z; // or
auto p = new derived_from_foo();
may cause undesired problems (corrupting memory, depending on the compiler, as I found out eventually). So my question: how can I write/design a derived class
struct bar // still abstract, since foo::job() is not provided
: foo
{
...
template<typename Derived, typename...Args>
static Derived* create(Args&&...args)
{
return ::new(foo::make_space(sizeof(Derived)))
Derived(std::forward<Args>(args)...);
}
};
such that construction of objects of type bar or any type derived from bar by any other means than through bar::create() fails at (i) compilation or (ii, less ideal) at run-time?
You can in fact enforce it, at a price.
Consider this class:
class A
{
public:
class Tag
{
public:
Tag(const Tag&) = default;
Tag(Tag&&) = default;
private:
Tag() {}
friend class A;
};
A(Tag, int a, char b) : a(a), b(b) {}
int a;
char b;
template<typename T, typename ... Params>
static T* make(Params&& ... params)
{
return new T(Tag(), std::forward<Params>(params)...);
}
};
Its constructor requires a Tag parameter, but you cannot make a Tag, it's got a private constructor. You can derive from A, but you cannot directly create objects of a derived class either: it needs to pass a Tag to its parent constructor, and you cannot make one.
So the only way to create an object of A or a derived class is by calling A::make.
Well there is still a way to cheat
class B : public A
{
public:
B(Tag t, double q) : A(t, 42, 'z'), q(q) {
// cheating:
B* other = new B(t, 3.14);
}
double q;
};
If this bothers you, you still can enforce correctness at run-time by making Tag non-reusable à la std::unique_ptr. Remove the copy ctor, throw in a private bool flag that you set on construction and clear on move-out, and check it inside make.
Related
As per [dcl.init.aggr] I cannot aggregate init a type, if it has (among other things) virtual functions, which includes inheriting from a type with a virtual destructor. However, I'd like to avoid having to write a ton of boilerplate constructors.
MWE:
struct Base {
virtual ~Base() {}
};
struct Derived : Base {
int i;
};
int main() {
Derived d1{42}; // not allowed in this fashion
Derived d2{{},42}; // also not allowed
}
In my setting I have a lot of types like Derived and they are all plain structs with a number of members (not necessarily trivial/pod) except for the fact that they have to inherit from Base.
Is there a way to avoid having to write Derived(int i) : Base(), i(i) {} constructors for all of them?
The one solution I could think of, is to exploit the fact that a struct without the inheritance above will gladly emit a default aggregate initialiser. So I compose that struct together with a templated wrapper type.
template <typename T>
struct BaseWrapper : Base, T {
BaseWrapper(T data) : Node(), T(data) {}
BaseWrapper() = delete;
BaseWrapper(BaseWrapper const&) = default;
BaseWrapper(BaseWrapper&&) = default;
BaseWrapper& operator=(BaseWrapper const&) = default;
BaseWrapper& operator=(BaseWrapper&&) = default;
static T const& cast(Base const& b) {
return static_cast<T const&>(static_cast<BaseWrapper<T> const&>(b));
}
static T& cast(Base& b) {
return static_cast<T&>(static_cast<BaseWrapper<T>&>(b));
}
};
And since I use the Derived types as shared pointers, a small convenience function:
template <typename T, typename... Args>
inline std::shared_ptr<BaseWrapper<T>> make_bw(Args&&... args) {
return std::make_shared<BaseWrapper<T>>(T{std::forward<Args>(args)...});
}
Allows us to create objects without the need of a dedicated constructor inside the object:
struct Derived { // note the missing : Base
int i;
};
auto p = make_bw<Derived>(42);
This is a bit of a cheaty solution, so a proper answer would still be useful.
Suppose I have the class
class A {
protected:
int x,y;
double z,w;
public:
void foo();
void bar();
void baz();
};
defined and used in my code and the code of others. Now, I want to write some library which could very well operate on A's, but it's actually more general, and would be able to operate on:
class B {
protected:
int y;
double z;
public:
void bar();
};
and I do want my library to be general, so I define a B class and that's what its APIs take.
I would like to be able to tell the compiler - not in the definition of A which I no longer control, but elsewhere, probably in the definition of B:
Look, please try to think of B as a superclass of A. Thus, in particular, lay it out in memory so that if I reinterpret an A* as a B*, my code expecting B*s would work. And please then actually accept A* as a B* (and A& as a B& etc.).
In C++ we can do this the other way, i.e. if B is the class we don't control we can perform a "subclass a known class" operation with class A : public B { ... }; and I know C++ doesn't have the opposite mechanism - "superclass a known class A by a new class B". My question is - what's the closest achievable approximation of this mechanism?
Notes:
This is all strictly compile-time, not run-time.
There can be no changes whatsoever to class A. I can only modify the definition of B and code that knows about both A and B. Other people will still use class A, and so will I if I want my code to interact with theirs.
This should preferably be "scalable" to multiple superclasses. So maybe I also have class C { protected: int x; double w; public: void baz(); } which should also behave like a superclass of A.
You can do the following:
class C
{
struct Interface
{
virtual void bar() = 0;
virtual ~Interface(){}
};
template <class T>
struct Interfacer : Interface
{
T t;
Interfacer(T t):t(t){}
void bar() { t.bar(); }
};
std::unique_ptr<Interface> interface;
public:
template <class T>
C(const T & t): interface(new Interfacer<T>(t)){}
void bar() { interface->bar(); }
};
The idea is to use type-erasure (that's the Interface and Interfacer<T> classes) under the covers to allow C to take anything that you can call bar on and then your library will take objects of type C.
I know C++ doesn't have the opposite mechanism - "superclass a known
class"
Oh yes it does:
template <class Superclass>
class Class : public Superclass
{
};
and off you go. All at compile time, needless to say.
If you have a class A that can't be changed and need to slot it into an inheritance structure, then use something on the lines of
template<class Superclass>
class Class : public A, public Superclass
{
};
Note that dynamic_cast will reach A* pointers given Superclass* pointers and vice-versa. Ditto Class* pointers. At this point, you're getting close to Composition, Traits, and Concepts.
Normal templates do this, and the compiler will inform you when you use them incorrectly.
instead of
void BConsumer1(std::vector<B*> bs)
{ std::for_each(bs.begin(), bs.end(), &B::bar); }
void BConsumer2(B& b)
{ b.bar(); }
class BSubclass : public B
{
double xplusz() const { return B::x + B::z; }
}
you write
template<typename Blike>
void BConsumer1(std::vector<Blike*> bs)
{ std::for_each(bs.begin(), bs.end(), &Blike::bar); }
template<typename Blike>
void BConsumer2(Blike& b)
{ b.bar(); }
template<typename Blike>
class BSubclass : public Blike
{
double xplusz() const { return Blike::x + Blike::z; }
}
And you use BConsumer1 & BConsumer2 like
std::vector<A*> as = /* some As */
BConsumer1(as); // deduces to BConsumer1<A>
A a;
BConsumer2(a); // deduces to BConsumer2<A>
std::vector<B*> bs = /* some Bs */
BConsumer1(bs); // deduces to BConsumer1<B>
// etc
And you would have BSubclass<A> and BSubclass<B>, as types that use the B interface to do something.
There is no way to change the behaviour of a class without changing the class. There is indeed no mechanism for adding a parent class after A has already been defined.
I can only modify the definition of B and code that knows about both A and B.
You cannot change A, but you can change the code that uses A. So you could, instead of using A, simply use another class that does inherit from B (let us call it D). I think this is the closest achievable of the desired mechanism.
D can re-use A as a sub-object (possibly as a base) if that is useful.
This should preferably be "scalable" to multiple superclasses.
D can inherit as many super-classes as you need it to.
A demo:
class D : A, public B, public C {
public:
D(const A&);
void foo(){A::foo();}
void bar(){A::bar();}
void baz(){A::baz();}
};
Now D behaves exactly as A would behave if only A had inherited B and C.
Inheriting A publicly would allow getting rid of all the delegation boilerplate:
class D : public A, public B, public C {
public:
D(const A&);
};
However, I think that could have potential to create confusion between code that uses A without knowledge of B and code that uses knows of B (and therefore uses D). The code that uses D can easily deal with A, but not the other way 'round.
Not inheriting A at all but using a member instead would allow you to not copy A to create D, but instead refer to an existing one:
class D : public B, public C {
A& a;
public:
D(const A&);
void foo(){a.foo();}
void bar(){a.bar();}
void baz(){a.baz();}
};
This obviously has potential to mistakes with object lifetimes. That could be solved with shared pointers:
class D : public B, public C {
std::shared_ptr<A> a;
public:
D(const std::shared_ptr<A>&);
void foo(){a->foo();}
void bar(){a->bar();}
void baz(){a->baz();}
};
However, this is presumably only an option if the other code that doesn't know about Bor D also uses shared pointers.
This seems more like static polymorphism rather dynamic. As #ZdeněkJelínek has already mentioned, you could you a template to ensure the proper interface is passed in, all during compile-time.
namespace details_ {
template<class T, class=void>
struct has_bar : std::false_type {};
template<class T>
struct has_bar<T, std::void_t<decltype(std::declval<T>().bar())>> : std::true_type {};
}
template<class T>
constexpr bool has_bar = details_::has_bar<T>::value;
template<class T>
std::enable_if_t<has_bar<T>> use_bar(T *t) { t->bar(); }
template<class T>
std::enable_if_t<!has_bar<T>> use_bar(T *) {
static_assert(false, "Cannot use bar if class does not have a bar member function");
}
This should do what you'd like (i.e. use bar for any class) without having to resort to a vtable lookup and without having the ability to modify classes. This level of indirection should be inlined out with proper optimization flags set. In other words you'll have the runtime efficiency of directly invoking bar.
Suppose I'm writing Derived and have to inherit from Base, which I don't control and has two separate constructors and a deleted copy and move constructors:
struct Base {
Base(int i);
Base(const char *sz);
Base(const Base&) = delete;
Base(const Base&&) = delete;
};
struct Derived {
Derived(bool init_with_string);
};
Now, depending on the value of another_param I have to initialize my base class using either a constructor or the other; if C++ was a bit less strict it would be something like:
Derived::Derived(bool init_with_string) {
if(init_with_string) {
Base::Base("forty-two");
} else {
Base::Base(42);
}
}
(this would also be useful for all the cases where it's cumbersome to calculate values to pass to base class constructors/fields initializers in straight expressions, but I'm digressing)
Unfortunately, even if I don't see particular codegen or object-model obstacles to this kind of thing, this isn't valid C++, and I cannot think of easy workaround.
Is there some way around this that I'm not aware of?
A static function will work fine here
struct Base {
Base(int i);
Base(const char *sz);
Base(const Base&) = delete;
Base(const Base&&) = delete;
};
struct Derived : Base {
using Base::Base;
static Derived construct(bool with_string) {
if(with_string) return { "forty-two" };
return { 42 };
}
};
Notice that this does not require a move, nor a copy constructor. If you want to have this as a local, you need to bind it to a reference in order to avoid moving it
auto &&w = Derived::construct(true);
auto &&wo = Derived::construct(false);
Not ideal but I have used this technique when nothing better suggested itself, when the initialization of an object had to occur inside a code block:
// (Same base as your code)
#include <memory>
struct Derived : public Base {
using Base::Base;
};
int main(int argc, char **argv)
{
std::unique_ptr<Derived> pd;
if ( argc == 2 )
{
pd = std::make_unique<Derived>(42);
}
else
{
pd = std::make_unique<Derived>("forty-two");
}
Derived &d = *pd;
// use d, don't manually reset pd
}
It's not really the answer you're looking for, but if you can get to a point where the decision is exposed to the code calling the constructor, you can use a tag-dispatch template constructor with a generic lambda for constexpr-if (bingo!), as follows:
#include <type_traits>
#include <memory>
struct Base {
Base(int) {};
Base(const char *) {};
Base(const Base&) = delete;
Base(const Base&&) = delete;
};
struct Derived : Base{
static std::unique_ptr<Derived> make_unique(bool init_with_string);
private:
template<typename init_with_string_t>
Derived(init_with_string_t);
};
template<typename init_with_string_t>
Derived::Derived(init_with_string_t) : Base([]{if constexpr(init_with_string_t::value) return "forty-two"; else return 42;}())
{
}
std::unique_ptr<Derived> Derived::make_unique(bool init_with_string)
{
if (init_with_string)
return std::unique_ptr<Derived>(new Derived(std::true_type{}));
else
return std::unique_ptr<Derived>(new Derived(std::true_type{}));
}
int main()
{
auto d1 = Derived::make_unique(true);
auto d2 = Derived::make_unique(false);
}
Live demo on wandbox
That's a C++17-heavy feature list, so clang 3.9 or gcc 7. As I did here, you can wrap up the tag-dispatch call with a factory, and if you make that a static member of the class, you can put the logic that selects whether to initialise with a string or a value in a private static class method, or inline in the factory method as you prefer.
Some less-than-pleasant issues I had to work around to get this working:
The type-dispatch is needed because even through we could have Derived's constructor be:
template<bool init_with_string>
Derived::Derived() : Base([]{if constexpr(init_with_string) return "forty-two"; else return 42;}())
{
}
there's actually no way to explicitly specify template parameters to a constructor, and template deduction cannot deduce non-type template parameters. (If you have access to a constexpr value in scope, you could probably do something like template<bool init_with_string = constexpr_bool_method()> but if you could do that, you could put that straight in the lambda.
The if constexpr lambda idea came from an answer to Equivalent ternary operator for constexpr if?, which would have been nicer.
Sadly, we can't use std::make_unique in a factory method to access private constructors, because friendship isn't transitive.
Edit: The following approach is quite close to what you are after, using placement new:
struct Derived3 : Base
{
Derived3::Derived3(bool init_with_string) : Base(42)
{
if(init_with_string)
{
// in case of any resources would have been allocated:
this->~Derived3();
new(this) Derived3("forty-two");
}
}
private:
using Base::Base;
};
First I construct a Base object with one of the two types. If the type condition does not match, I need to destroy it again calling the destructor explicitly to avoid undefined behaviour (and to prevent leaks in case that Base allocated memory already). Afterwards, we can reconstruct the class using the other constructor. Well, and this is the drawback of this approach, we potentially allocate some memory in vain, just to release it afterwards again and then re-allocate it! At least, we create an object in vain in some of the cases.
So no non-plus-ultra solution, so I'll leave my previous approaches:
Currently offering two approaches, both not really what you are after, but for now, I did not get closer...
Well, the obvious and easy solution:
struct Derived1 : Base
{
static Derived1* instance(bool init_with_string)
{
return init_with_string ? new Derived1("forty-two") : new Derived1(42);
}
private: // or even not, then you can construct your derived classes directly...
using Base::Base;
};
int main(int argc, char* argv[])
{
Derived1* d1 = Derived1::instance(false);
}
Template variant:
struct Derived2 : Base
{
private:
using Base::Base;
template <bool>
friend struct Derived2Maker;
};
template <bool InitWithString>
struct Derived2Maker : Derived2
{
Derived2Maker() : Derived2(42) { }
};
template <>
struct Derived2Maker<true> : Derived2
{
Derived2Maker() : Derived2("forty-two") { }
};
int main(int argc, char* argv[])
{
Derived2* d2 = new Derived2Maker<false>();
}
Drawback: boolean parameter must be known at compile time...
Honestly you should just respect the implementation of Base and let Derived have two constructors.
class Derived : Base {
Derived(int i) : Base(i) {}
Derived(const char *s) : Base(s) {}
}
Then as Johannes Schaub remarked it's actually possible to have an external make_derived() using initializer lists even without copy constructors.
Say that I have a void* containing a pointer to an unknown class. I want to use dynamic_cast to do run-time checking on the type of class I actually have. For example:
class Foo {};
void* bar = new Foo;
If I attempt to do dynamic_cast<Foo*>(bar) I get:
'void *': invalid expression type for dynamic_cast
However I need dynamic_cast because in my actual situation I'm not sure that bar is in fact a Foo*.
I've read here that one solution to this is to create a base class for all objects that bar could contain, reinterpret_cast to a pointer to that base class, and then try to dynamic_cast from that object pointer to Foo.
This is difficult for me because the objects that may be stored in bar are not all under my control. (And cause trying to recreate Java gives me heartburn.) Is there another way to do this?
dynamic_cast is use to cast down a polymorphic object to a class that has the type of the object you're trying to cast as it's parent.
void* is completely different from that.
with a pointer to void, you are literally stripping every type information away.
dynamic_cast know that there's a base class and can do type checking through RTTI.
When you cast down a void pointer, you're saying to the compiler: "yeah you know this place in the memory? well, use it as this type" and if the memory is invalid, UB is invoked.
you have three choices here.
Option 1
Use an interface.
Well, a polymorphic base class is the only way to do a dynamic_cast. There is no other way, no hacks, it's the only way. Simple as that.
struct Base { virtual ~Base() = default; };
struct Derived : Base {};
// ...
void test (Base* base) {
auto derived = dynamic_cast<Derived*>(base);
if (derived) {
// derived is valid here.
}
}
Option 2
Identify the type with the pointer
I use a method to have a unique identifier per type and use the identifier to validate the cast. Done without any RTTI
using type_id_t = void(*)();
template <typename T> void type_id() {}
// now we can use a map or a vector.
std::vector<std::pair<type_id_t, void*>> vec;
template<typename T>
void insertToMyVector(T* obj) {
vec.emplace_back(type_id<T>, obj);
}
template<typename T>
T* getObj(int index) {
auto item = vec[index];
return static_cast<T*>(item.first == &type_id<T> ? item.second : nullptr);
}
// ...
int main () {
auto foo = new Foo;
insertToMyVector(foo);
auto maybeFoo = getObj<Foo>(0);
if (maybeFoo) {
// you have a valid Foo here
}
}
Option 3
Generate derived class for any type
This one is quite useful as it can hold any type while keeping type safety. I look like solution 1 but offer more flexibility. The trick it to generate a derived class for any type using templates. The advantage is you can hold any type, but may complexify you cade a bit.
struct Base { virtual ~Base() = default; };
template<typename T>
struct Derived : Base {
Derived(T&& obj) : _obj{std::move(obj)} {}
Derived(const T& obj) : _obj{obj} {}
T& get() {
return _obj;
}
const T& get() const {
return _obj;
}
private:
T _obj;
};
// ...
void test (Base* base) {
auto derived = dynamic_cast<Derived<int>*>(base);
if (derived) {
int i = derived->get();
// derived is valid here, and we can safely access the int
}
}
To ensure dynamic_cast compiles and works, you should create an abstract or interface class with a virtual method.
#include <cassert>
class Bar
{
public:
Bar() = default;
virtual ~Bar() = default;
};
class Foo : public Bar
{
public:
Foo() = default;
virtual ~Foo() = default;
};
int main()
{
Bar* bar = new Foo;
Foo* foo = dynamic_cast<Foo*>(bar);
assert(foo != nullptr);
}
As I understand it you want a polymorphic object but no common base class.
There is already a fairly standard idiom for this - it's called boost::any.
A boost::any carries your object plus some type information. The interface allows you to query the type and to attempt to cast the any to the type you're looking for.
http://www.boost.org/doc/libs/1_59_0/doc/html/any.html
I run into a trouble with templates and inheritance. Consider following code:
#include <iostream>
using namespace std;
class TemplateBase {
public:
TemplateBase() {}
};
class TemplateA: public TemplateBase {
public:
TemplateA():TemplateBase() {}
};
template <class T>
class Base {
public:
Base() {}
};
class Derived: public Base<TemplateA> {
public:
Derived(): Base() {}
};
int main()
{
Base<TemplateBase>* a = new Base<TemplateBase>(); // ok
Base<TemplateA>* b = new Derived(); // ok
Base<TemplateBase>* c = new Derived(); // error: cannot convert ‘Derived*’ to ‘Base<TemplateBase>*’ in initialization
}
The problem is the assignment of pointer c, which fails from unknown reason for me. I am trying to assign the Derived<AnotherDerived> to Base<AnotherBase>, is this possible?
Thank you for any help.
Your Derived is a non-template class derived from Base<TemplateA>. In the line
Base<TemplateBase>* c = new Derived();
you are trying to refer to a Derived object via a pointer to Base<TemplateBase>. For the compiler, there is no relation between Base<TemplateBase> and Derived, hence it fails. The only possible base to use is Base<TemplateA> from which Derived is derived.
A possible solution is to templatize the Derived, like
template<typename T>
class Derived: public Base<T> {
public:
Derived(): Base<T>() {}
};
then use as
Base<TemplateBase>* c = new Derived<TemplateBase>;
See a live example here.
vsoftco gives a good outline of why this is invalid. An example of why this is the case in C++ is that although TemplateBase and TemplateA are related, Base<TemplateBase> and Base<TemplateA> are completely different. We could even specialize Base in a way which makes them have an incompatible interface:
template<>
struct Base<TemplateBase>
{
Base() = delete;
Base(int i) {}
}
Now it's obvious that Base<TemplateBase> and Base<TemplateA> can't be used in the same way, because one is default-constructable and one isn't. As such, it's impossible to use them polymorphically, because the compiler won't know what code to generate.
Polymorphism says a base class pointer can point to a derived class object.
But the same can't happen for templates.
Since Polymorphism is a dynamic feature and bound at run-time.
Templates are a static feature and bound at the compile time.
You make a common mistake, you think that relation between classes:
class A {};
class B : public A {};
Will propagate this relation to templates:
template <class T>
class Tmpl {};
Tmpl<A> a; Tmpl<B> b;
a = b; // fails!
So you expected that Tmpl<A> would be a parent to Tmpl<B> but that is not the case. To simulate that you would need to make a constructor, that allows such conversion:
template <class T>
class Tmpl {
T data;
public:
Tmpl() : data() {}
template<class Parent>
Tmpl( const Tmpl<Parent> &t ) : data( t.data ) {}
};
Tmpl<A> a; Tmpl<B> b;
a = b; // works!
For details you should look into smart pointer implementation, there is similar problem there - assignment from pointer to child from base needs to work.
The Derived class is derived from Base<TemplateA> so Base<TemplateBase>* c = new Derived() is equivalent to saying
Base<TemplateBase>* c = new Base<TemplateA>() which is incorrect because Base<TemplateA> is a different class altogether.
TemplateBase is a base class for TemplateA but same does not hold true for Base<TemplateBase> and Base<TemplateA>.