I am working with a set of classes A, B, ... These classes are independent except that they have one method in common. Now I want to combine these classes in a vector, to call method in one loop. It seems that the best solution is to make the classes derived classes from some Parent (see below).
Now the question is the following. I want to create a header-only library for each class (a.h, b.h, ...). There I want the classes to be completely independent. Only in the main module I want to 'attach' the classes to a Parent to be able to combine them in a vector. How do I do this? Or do I have to resort to a vector of void* pointers? Or is there another way to combine these classes in a vector?
Classes in list: with parent/child paradigm
Here is what I have been able to do to combine the classes in the vector. Note I specifically want to avoid the parent/child paradigm in the class definitions. But I still want to combine them in a vector.
#include <iostream>
#include <vector>
#include <memory>
class Parent
{
public:
virtual ~Parent(){};
virtual void method(){};
};
class A : public Parent
{
public:
A(){};
~A(){};
void method(){};
};
class B : public Parent
{
public:
B(){};
~B(){};
void method(){};
};
int main()
{
std::vector<std::unique_ptr<Parent>> vec;
vec.push_back(std::unique_ptr<Parent>(new A));
vec.push_back(std::unique_ptr<Parent>(new A));
vec.push_back(std::unique_ptr<Parent>(new B));
for ( auto &i: vec )
i->method();
return 0;
}
Compile using e.g.
clang++ -std=c++14 main.cpp
A possible solution based on type erasure, static member functions and pointers to void that doesn't make use of virtual at all (example code, far from being production-ready):
#include <iostream>
#include <vector>
struct Erased
{
using fn_type = void(*)(void *);
template<typename T>
static void proto(void *ptr) {
static_cast<T*>(ptr)->method();
}
fn_type method;
void *ptr;
};
struct A
{
void method(){ std::cout << "A" << std::endl; };
};
struct B
{
void method(){ std::cout << "B" << std::endl; };
};
int main()
{
std::vector<Erased> vec;
vec.push_back(Erased{ &Erased::proto<A>, new A });
vec.push_back(Erased{ &Erased::proto<B>, new B });
for ( auto &erased: vec ) {
erased.method(erased.ptr);
}
return 0;
}
This can help to avoid using a common base class. See it on wandbox.
As mentioned in the comments, here is a slightly modified version that adds create and invoke methods to reduce the boilerplate for the users.
This is more of a pseudocode, trivial details are omitted.
struct HolderBase
{
virtual void foo() = 0;
};
template <class T>
struct Holder : HolderBase
{
Holder(T* t) : t(t) {}
T* t;
void foo() { t->foo(); }
};
std::vector<HolderBase*> v { new Holder<A>(new A), new Holder<B>(new B) };
You can also have a variant of Holder that holds an object by value (and mix both variants in the same vector freely).
If you have a single method to call, there is a much simpler solution:
A a;
B b;
std::vector<std::function<void()> v { [](){a.foo();}, [](){b.foo();} };
You want to erase the type of the objects and treat them uniformly, so naturally type erasure is the solution.
class with_method_t {
struct model_t {
virtual ~model_t() = default;
virtual void call_method() = 0;
};
template<class C>
class concept_t final : public model_t {
C obj;
public:
concept_t(C const& c) : obj{c} {}
concept_t(C&& c) : obj{std::move(c)} {}
void call_method() override { obj.method(); }
};
std::unique_ptr<model_t> instance;
public:
template<class C>
with_method_t(C&& arg)
: instance{std::make_unique<concept_t<C>>(std::forward<C>(arg))}
{}
void method() { instance->call_method(); }
};
Then have yourself a vector of with_method_t which is a value type. No raw dynamic allocation or de-allocation. The instance is build by forwarding the argument it receives into a small polymorphic container:
std::vector<with_method_t> vec;
vec.emplace_back(A{});
vec.emplace_back(B{});
for ( auto &i: vec )
i.method();
Related
Currently, I store pointers of different types in a vector. To archive this, I implemented a class template "Store" which derives from a non-class template "IStore". My vector finally stores pointers to "IStore".
In code:
class IStore
{
public:
IStore() = default;
virtual ~IStore() = default;
virtual void call() = 0;
// ... other virtual methods
};
template<typename T>
class Store : public IStore
{
public:
Store() = default;
virtual ~Store() = default;
virtual void call() override;
// ... other virtual methods
private:
T* m_object = nullptr;
}
And in my main class which holds the vector:
class Main
{
public:
template<typename T>
void registerObject(T* ptr);
template<typename T>
void callObjects();
// ... other methods
private:
std::vector<IStore*> m_storedObjects;
};
So far the current class structure. To describe the problem I need to introduce the following three example structs:
struct A {}
struct B : public A {}
struct C : {}
Other classes should call the Main::registerObject method with pointers to objects of A, B or C types. This method will then create a new Store<A>, Store<B> resp. Store<C> template class object and inserts this objects pointer to m_storedObjects.
Now the tricky part starts: The method Main::callObjects should be called by other classes with a template argument, such as Main::callObjects<B>(). This should iterate though m_storedObjects and call the IStore::call method for each object, which is of type B or which type B is derived from.
For example:
Main::registerObject<A>(obj1);
Main::registerObject<B>(obj2);
Main::registerObject<C>(obj3);
Main::callObjects<B>();
Should call obj1 and obj2 but not obj3, because C isn't B and B isn't derived from C.
My approaches in Main::callObjects were:
1. Perform dynamic_cast and check against nullptr like:
for(auto store : m_storedObjects)
{
Store<T>* base = dynamic_cast<Store<T>*>(store);
if(base)
{
// ...
}
}
which will only work for the same classes, not derived classes, because Store<B> isn't derived from Store<A>.
2. To overwrite the cast operator in IStore and Store, such that I can specify Store should be castable when the template argument is castable. For example in Store:
template<typename C>
operator Store<C>*()
{
if(std::is_convertible<T, C>::value)
{
return this;
}
else
{
return nullptr;
}
}
But this method is never called.
Does anyone have a solution to this problem?
Sorry for the long post, but I thought more code would be better to understand the problem.
Thanks for your help anyway :)
After some thought, I realized that your type erasure, from assigning Store<T> objects to IStore* pointers, makes it impossible to use any compile-time type checking like std::is_base_of and the like. The next best option you have is run-time type information (dynamic_cast<>(), typeid()). As you observed, dynamic_cast<>() can't determine if an object's type is an ancestor of another type, only if an object's type is a descendant of another type known at compile time.
EDIT: With C++17 support, I can think of another way to solve your problem, based on the std::visit example here. If you change your Main interface...
#include <iostream>
#include <vector>
#include <variant>
template <typename T>
class Store {
public:
using value_type = T;
Store(T* object): m_object(object) {}
void call() { std::cout << "Hello from " << typeid(T).name() << '\n'; }
// ... other methods
private:
T* m_object = nullptr;
};
template <typename... Ts>
class Main {
private:
std::vector<std::variant<Store<Ts>...>> m_storedObjects;
public:
// replacement for registerObjects, if you can take all objects in at once
Main(Ts*... args): m_storedObjects({std::variant<Store<Ts>...>(Store<Ts>{args})...}) {}
template <typename U>
void callObjects() {
for (auto& variant : m_storedObjects) {
std::visit([](auto&& arg) {
using T = typename std::decay_t<decltype(arg)>::value_type;
if constexpr (std::is_base_of<T, U>::value) {
arg.call();
}
}, variant);
}
}
};
struct A {};
struct B : public A {};
struct C {};
int main() {
A a;
B b;
C c;
auto m = Main{&a, &b, &c};
m.callObjects<B>();
// > Hello from 1A
// > Hello from 1B
return 0;
}
In an example below I have a pretty typical CRTP example, two different derived classes that both have a method bar. The base class has a method foo which just forwards to some derived bar method
#include <iostream>
template<typename Derived>
class Base {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
class DerivedA : public Base<DerivedA> {
public:
void bar() {
::std::cout << "A\n";
}
};
class DerivedB : public Base<DerivedB> {
public:
void bar() {
::std::cout << "B\n";
}
};
int main() {
DerivedA a;
DerivedB b;
a.foo();
b.foo();
}
It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?
You can use Boost.Variant. For example:
typedef boost::variant<DerivedA, DerivedB> Derived;
struct BarCaller : public boost::static_visitor<void> {
template <class T>
void operator()(T& obj) {
obj.bar();
}
};
int main() {
std::vector<Derived> vec{DerivedA(), DerivedB(), DerivedA()};
BarCaller bar;
for (Derived& obj : vec) {
obj.apply_visitor(bar);
}
}
This lets you store heterogeneous types in a vector or other STL container (by using a "discriminated union"), and lets you call a specific function on all of them regardless of their not having a common ancestor or any virtual methods.
It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different.
You can have a base class of Base<T> for all T, then, you can have a list/vector/array of pointers to the base class, if that works for you.
struct BaseOne
{
virtual void foo() = 0;
virtual ~BaseOne() {}
};
template<typename Derived>
class Base : struct BaseOne {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
and then,
int main() {
std::vector<BaseOne*> v {new DerivedA, new DerivedB };
for ( auto item : v )
item->bar();
for ( auto item : v )
delete item;
}
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?
No, there isn't.
As per now, variant has became part of the C++17 standard and the solution to the problem can be solved by std::variant and std::visit as follows.
The template class in the example is Interface<> and use the CRTP idiom to force derived class to implement helloImpl():
#include <iostream>
#include <vector>
#include <variant>
template<typename Implementer>
struct Interface {
void hello() const {
static_cast<Implementer const *>(this)->helloImpl();
}
};
A couple of class examples with different implementations of helloImpl()
struct Hello1 : public Interface<Hello1> {
void helloImpl() const {
std::cout << "Hello1" << std::endl;
}
};
struct Hello2 : public Interface<Hello2> {
void helloImpl() const {
std::cout << "Hello2" << std::endl;
}
};
And here is how to use it to store data in a vector<> container and its traversal:
int main() {
using var_t = std::variant<Hello1, Hello2>;
std::vector<var_t> items{Hello1(), Hello1(), Hello2()};
for(auto &item: items) {
std::visit([](auto &&arg) {
arg.hello();
}, item);
}
return 0;
}
Is it possible to pass this by default ?
Here is what I currently have
class A
{
public:
template<typename T>
void dowithT(T t) {}
};
class B
{
public:
A a;
B()
{
//Calling 'dowithT' with 'this'
a.dowithT(this);
}
};
This function requires passing this from the caller of the function every time. So I wondered if there is a way to encapsulate this task, so that you don't need to pass this to dowithT.
I tried to do something like this:
class A
{
public:
// '= this' doesn't compile
template<typename T>
void dowithT(T t = this) {}
};
class B
{
public:
A a;
B()
{
//Calling 'dowithT' without 'this'
a.dowithT();
}
};
Unfortunately, I can't use templates, so my first solution isn't an option.
Is this possible?
Edit: I gave a concrete answer with my own implementation below. Also with a few mor deatils of what I wanted in the end.
TL;DR No, this is not possible.
this is not the same type in every class, you can't generalize it, so no, not possible.
Additionally, what would this be if doWithT() was called from a non-member function? nullptr?
That's why it isn't possible. You have to use a template.
Instead of B having a member of type A, it can inherit from A, and use something like the "curiously recurring template pattern."
If you cannot make class A a template, you can still do it like so:
class A
{
protected:
template <class T>
void dowithT()
{
T* callerthis = static_cast<T*>(this);
// callerthis is the "this" pointer for the inheriting object
cout << "Foo";
}
};
class B : public A
{
public:
B()
{
dowithT<B>();
// Or A::dowithT<B>();
}
};
dowithT() must only be called by an inheriting class (hence I made it protected), with the template parameter the caller's own type, or you'll break everything.
You may achieve exactly what you want by using a private mixin class to provide the dowithT method that takes no arguments:
#include <iostream>
#include <typeinfo>
class A
{
public:
template<typename T>
void dowithT(T* t) {
std::cout << "Hello, World" << typeid(*t).name() << std::endl;
}
};
template<class Owner>
struct calls_a
{
void dowithT()
{
auto p = static_cast<Owner*>(this);
p->a.dowithT(p);
}
};
class B
: private calls_a<B>
{
friend calls_a<B>;
A a;
public:
B()
{
//Calling 'dowithT' with 'this'
dowithT();
}
};
int main()
{
B b;
}
No, it is not possible. There is nothing really special about this when used as an argument to a function taking T* (template or not), it's just a pointer like any other.
this A is different from this B. In your first code, this refers to the caller, while in the second this refers to the callee. Thus what you want to do isnt really possible.
Here's one possibility, which might, or might not suit your needs:
template<typename T>
class A
{
public:
A(T t) : t(t) {}
void dowithT()
{
cout << "Foo";
}
private:
T t;
};
class B
{
public:
A<B*> a;
B() : a(this)
{
a.dowithT();
}
};
You could use a private method in class B that acts as a relay, and use the constant nullptr as a special value for this, if you want to be able to pass other values:
class B
{
public:
A a;
B()
{
//Calling 'dowithT' with 'this'
innerdo();
}
private:
void innerdo(B *p = nullptr) {
if (p == nullptr) p = this;
a.dowithT(p);
}
};
If you only need to pass this it is even simpler
void innerdo() {
a.dowithT(this);
}
After trying out various things you mentioned, I'd like to give my answer/solution to the problem myself to clarify some details:
#include <iostream>
using namespace std;
#include <functional>
template <typename CallerType>
class AFunctionConstructor{
private:
virtual void abstr()
{}
public:
typedef void(CallerType::*CallerTypeFunc)();
function<void()>* constructFunction(CallerTypeFunc func)
{
CallerType* newMe = dynamic_cast<CallerType*> (this);
return new function<void()>(std::bind(func,newMe));
}
};
class A : public function<void()>
{
protected:
public:
A();
A(function<void()>* func) : function<void()>(*func)
{}
};
// now create ressource classes
// they provide functions to be called via an object of class A
class B : public AFunctionConstructor<B>
{
void foo()
{
cout << "Foo";
}
public:
A a;
B() : a(constructFunction(&B::foo)) {}
};
class C : public AFunctionConstructor < C >
{
void bar()
{
cout << "Bar";
}
public:
A a;
C() : a(constructFunction(&C::bar)) {}
};
int main()
{
B b;
C c;
b.a();
c.a();
cout << endl;
A* array[5];
array[0] = &b.a; //different functions with their ressources
array[1] = &c.a;
array[2] = &b.a;
array[3] = &c.a;
array[4] = &c.a;
for (int i = 0; i < 5; i++) //this usability i wanted to provide
{
(*(array[i]))();
}
getchar();
return 0;
}
Output :
FooBar
FooBarFooBarBar
This is as far as i can press it down concerning examples. But i guess this is unsafe code. I stumbled across possible other and simpler ways to achieve this (other uses of std::function and lambdas(which i might have tried to reinvent here partially it seems)).
At first I had tried to pass "this" to the bind function in function<void()>*AFunctionConstructor::constructFunction(CallerTypeFunc func)
,though, which i now get through the dynamic upcast.
Additionally the functionality of AFunctionConstructor was first supposed to be implemented in a Constructor of A.
class A
{
public:
int x;
//create a vector of functors in B and C here
};
class B
{
public:
struct bFunctor
{
void operator()() const
{
//some code
}
};
};
class C
{
public:
struct cFunctor
{
void operator()() const
{
//some code
}
};
};
void main()
{
A obj;
//iterate through the vector in A and call the functors in B and C
}
My question is what should be the format of the vector in class A for calling functors in B and C? Or is the only way this is possible to have a base functor in A and make the functors in B and C derive from it? Or is there a better approach?
There are essentially two ways to approach this (that I can think of ATM):
Note: I would rename cFunctor and bFunctor to simply Functor in both cases. They are nested inside respective classes and thus such prefix makes little sense.
Type erased
Example of type erasure is std::function.
class A {
public:
int x;
std::vector<std::function<void(void)>> functors;
A() : functors { B::bFunctor(), C::cFunctor() }
{ }
};
If you need the functors to have more advanced behaviour, Boost.TypeErasure any might help.
Polymorphic
Create an abstract functor type.
Make B::bFunctor and C::cFunctor inherit from it.
Store vector of that abstract functor type smart pointers.
struct AbstractFunctor {
virtual void operator()() const = 0;
};
class B {
public:
struct Functor : public AbstractFunctor {
void operator()() const {
//some code
}
};
};
class A {
public:
int x;
std::vector<std::unique_ptr<AbstractFunctor>> functors;
A() {
// this could most probably be shortened with make_unique
functors.emplace_back(std::unique_ptr<AbstractFunctor>(new B::Functor()));
functors.emplace_back(std::unique_ptr<AbstractFunctor>(new C::Functor()));
}
};
Imagine I have a class 'BaseA' that contains a collection of items 'ItemA'.
Now I want to extend 'BaseA' to add extra capabilities, so I derive 'DerivedA' from 'BaseA'.
One characteristic of 'DerivedA' is that it has to handle more sophisticated 'DerivedITemA' items instead of 'ItemA' ones.
class BaseA {
protected:
vector<ItemA> x;
void m1(int i) { x.m1(i); }
};
class ItemA {
protected:
void m1(int i) { ... }
};
class DerivedItemA : public ItemA {
void m2(int i) { ... }
};
Now I would like to handle something of this sort:
class DerivedA : public BaseA {
vector<DerivedItemA> x;
void m2(int i) { x[i].m2(); }
};
I.e. have my Derived class handle derived items. The above definition of x is incorrect as it clashes with the one in BaseA. But the idea is I want to be able to reuse all methods in BaseA that handle x as long as they deal with ItemA elements and have the extended methods in DerivedA to handle the extra intricacies of DerivedItemA type of data
Any suggestion? My current thoughts are in the lines of defining a new datatype for x (VectorOfItemA for instance) and derive from it VectorOfDerivedItemA. I wonder if there is a simpler / better solution.
Thanks
I believe you need to have pointers in your vectors in order to handle this. I'm a little confused what value to pass to m1 and m2 since i appears to be an index, but here's my guess:
class BaseA {
protected:
vector<ItemA*> x;
void m1(int i) { x[i]->m1(i); }
};
class ItemA {
protected:
void m1(int i) { ... }
};
class DerivedItemA : public ItemA {
void m2(int i) { ... }
};
class DerivedA : public BaseA {
vector<DerivedItemA*> y; //don't shadow the base class vector!
void m2(int i) { y[i]->m2(i); }
};
Then, when you add an item in DerivedA, add it to both x and y. That way BaseA can do it's thing to the pointer in x and DerivedA can do its thing on the pointer in y.
Edit: you'll also need to provide a virtual method for adding items otherwise you might get things added to BaseA.x that don't get added to DerivedA.y.
Do you own all the classes? If so, you can refactor into a template base class instead.
template <typename ITEM>
class BaseT {
protected:
vector<ITEM> x;
void m1(int i) { x[i].m1(); }
};
typedef BaseT<ItemA> BaseA;
class DerivedA: public BaseT<DerivedItemA> {
void m2(int i) { x[i].m2(); }
};
If you intend to re-use code that takes BaseA to also accept a DerivedA, then you may need to modify them to be template functions/classes as well.
Otherwise, you will need some kind of "polymorphic" base object for the vector. You can look at Retrieve data from heterogeneous std::list (or my follow up question: unique_ptr member, private copy constructor versus move constructor) for one such approach.
As an alternative to a polymorphic item, you can define an interface for your base.
class BaseI {
protected:
virtual void m1(int) = 0;
//... other interfaces
public:
virtual ~BaseI () {}
//... other public interfaces
};
template <typename ITEM>
class BaseT : public BaseI {
protected:
vector<ITEM> x;
void m1(int i) { x[i].m1(); }
//...implement the other interfaces
};
//...
Now, code that takes a BaseA needs to be refactored to take a BaseI instead. That new code will be able to accept a DerivedA as well.
You may try to use Curiously Recurring Template Pattern - CRTP:
live demo
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;
struct Item
{
void m1(int i)
{
cout << "m1(" << i << ")" << endl;
}
};
struct DerivedItem : Item
{
void m2(int i)
{
cout << "m2(" << i << ")" << endl;
}
};
template<typename Derived>
struct IBase
{
void m1(int i)
{
for(auto &&z : static_cast<Derived*>(this)->x)
{
z.m1(i);
}
}
};
template<typename Derived>
struct IDerivedBase: IBase<Derived>
{
void m2(int i)
{
for(auto &&z : static_cast<Derived*>(this)->x)
{
z.m2(i);
}
}
};
struct Base : IBase<Base>
{
vector<Item> x;
};
struct DerivedBase : IDerivedBase<DerivedBase>
{
vector<DerivedItem> x;
};
int main()
{
Base b;
b.x.resize(3);
DerivedBase d;
d.x.resize(1);
b.m1(11);
d.m1(22);
d.m2(33);
}
Output is:
m1(11)
m1(11)
m1(11)
m1(22)
m2(33)
Vector will contain either all elements as ItamA in BaseA instantiations or all elements of DerivedItemA in DerivedA instantiaions. There is no need to mix.
There is no any mix at this approach:
Base has only vector<Item> providing m1 method
DerivedBase has only vector<DerivedItem> providing m1 and m2 methods.
However, without knowing real usage pattern - it is hard to guess what you need. Maybe for your case two standalone vectors would be enough:
vector<Item> x1;
vector<DerivedItem> x2;
and just define stand-alone functions for them.