Retrieve objects pointers of different type - c++

Consider I have a bunch pointers to to different objects of different classes
class1* obj1;
class2* obj2;
class3* obj3;
and they all have one method getArray() which returns a vector for post processing.
if all of these pointers are stored in some sort of a list (a list of void pointers say)
while I am iterating the list is there a way to figure what type of a pointer cast can be used?
I understand this can be solved by class hierarchy and deriving the above classes from a single class. Since a lot of it is legacy code can something like what is mentioned be done?
Folly dynamic does not let me store pointers, thats one thing that is tried

If getArray() always has the same signature (or similar enough to cast to the same type) - what you could do is create a class hierarchy for a decorator of the duck-typed legacy objects/classes. You can use a template derived class of a non-template interface to wrap without too much typing work.
Something along these lines (with more defensive coding, possibly smart pointers to the legacy object, etc. etc.):
class IDecorator {
public:
virtual std::vector<ubyte> GetArray() = 0;
};
template<typename TLegacyType>
class TDecorator : public IDecorator {
public:
TDecorator(const TLegacyType *ip_legacy_object)
: mp_legacy_object(ip_legacy_object) {}
std::vector<ubyte> GetArray() override {
return mp_legacy_object->GetArray();
}
private:
const TLegacyType *mp_legacy_object;
};

template<class R, class Op>
struct any_ptr {
void* ptr=0;
R(*f)( void* ) = 0;
R operate() const { return f(ptr); }
explicit operator bool() const { return ptr; }
template<class T>
T* as() const { return static_cast<T*>(ptr); }
any_ptr(any_ptr const&)=default;
any_ptr& operator=(any_ptr const&)=default;
any_ptr()=default;
template<class T>
any_ptr(T* p_in):ptr(p_in),
f( [](void* ptr)->R{ return Op{}( ptr ); } )
{}
};
any_ptr supports storing any pointer that supports Op, where Op is a stateless function object type returning R.
struct get_array_t{
template<class T>
auto operator()(T* t)const{ return t->getArray(); }
};
using any_ptr_get_array = any_ptr< std::vector<int>, get_array_t >;
now any_ptr_get_array can store a pointer to any type that supports .getArray() that returns vector<int>.
To call getArray:
void test(any_ptr_get_array ptr){
if(ptr){
auto vec = ptr.operation();
}
}
This technique could be called manual type erasure using a template generated vtable.

Related

Is it possible to cast from vector parent* to vector child* in a function without using templates

While working on a data import system I decided to store a lot of objects deriving from one class in a vector of pointers to the parent class. And then I would like to have a function that returns a vector of any type of child pointers (using paramaters that let me know what kind of child it is).
I managed to realize a similar and simplified code here, but it uses templates and casts and I feel like only casts could be enough. However the compiler does not want to do any cast from vector A* to vector B*.
EDIT: In the real code there are many child classes, not only B, so replacing the template by B is not an option, sorry for not being precise enough.
#include <vector>
using namespace std;
class A
{
public:
int attr;
A(): attr(1) {}
};
class B : public A
{
public:
B(): A() {attr = 2;}
};
template <typename O>
vector<O*> bees(vector<A*> vecA)
{
auto vecO = vector<O*>();
for (auto it = vecA.begin(); it != vecA.end(); it++)
{
if ((*it)->attr == 2)
{
vecO.push_back(reinterpret_cast<O*>(*it));
}
}
return vecO;
}
int main()
{
auto vecA = vector<A*>();
vecA.push_back(new A());
vecA.push_back(new B());
vecA.push_back(new B());
vector<B*> vecB = bees<B>(vecA);
}
So my question is : Is it possible to have a code do the same effect without using templates ? And if not does the compiler generate specific code with this one ? Knowing there would be theorically no difference in runtime no matter the template.
Thank you.
Since you want a function that can return vector of any type of child pointer so i believe template is needed to specify child type but certain things like reinterpret_cast etc. is not needed and here is sample implementation :
class A
{
public:
int attr;
A(): attr(1) {}
virtual ~A() {};
};
class B : public A
{
public:
B(): A() {attr = 2;}
};
template<typename T>
vector<T*> bees(const vector<A*> &vecA)
{
vector<T*> vec;
for (auto it = vecA.begin(); it != vecA.end(); it++)
{
T* ptr = dynamic_cast<T*>(*it);
if(ptr != nullptr)
{
vec.push_back(*it);
}
}
return vec;
}
We are using dynamic_cast because we are downcasting parent type to child type.Also for dynamic_cast to work we need virtual destructor/virtual function as it require RTTI
Inheritance and polymorphy are supposed to hide away different child types, so the rest of your code doesn't have to worry about specific types.
Casting objects to specific types is very likely not the right approach to whatever you're trying to do. Let the types decide how they are used and what they do, not the outside world.
If you want to filter a vector to get only objects with specific properties, you shouldn't look at their types, you should ask them if they have the properties you are looking for:
void FilterA(const std::vector<A>& source, std::vector<A>& destination, std::function<bool(const A&)> filter) {
std::copy_if(source.begin(), source.end(), std::back_inserter(destination), filter);
}
Then you can call it like this:
std::vector<A> filteredVecA;
FilterA(vecA, filteredVecA, [](const A& a){return a.HasSomePropertyYouCareAbout();});
You should consider moving the type checking inside the hierarchy (this uses templates, but no casts):
class A {
public:
virtual ~A(); // you _are_ in a hierarchy of objects
template<typename T>
virtual T* as() const { return nullptr; }
};
template<typename X>
class Convertible: public A {
template<typename T>
virtual T* as() const {
if constexpr(std::is_same_v<X, T>)
return this;
else
return nullptr;
}
};
class B: public Convertible<B> {
};
template <typename O>
vector<O*> bees(vector<A*> vecA)
{
auto vecO = vector<O*>();
foreach (auto ptr: vecA)
{
auto ptrO = ptr->as<O>();
if (ptrO)
vecO.push_back(ptrO);
}
return vecO;
}
Some points:
OP's comment:
I am using reinterpret cast because it I do not cast it just doesn't compile, and it feels to me like it is the most adequate here knowing I do not need to do any changes on the object.
dynamic_cast is usually a symptom of an insufficiently designed class hierarchy. Whenever you think "I can solve this with dynamic_cast" consider adding code to your class hierarchy instead.

C++ avoid call to abstract base class's constructor

Currently, I am building a library in C++ (using C++11 standards), and I am stuck on trying to figure out how to make my design more practical. I have the following abstract class E
template<typename K>
class E
{
public:
virtual ~E() {};
virtual void init() = 0;
virtual void insert(const K& k) = 0;
virtual size_t count() const = 0;
virtual void copy(const E<Key>& x) = 0;
};
which I want to restrict users from instantiating it (i.e., be an interface). E has two sub-classes that implement the corresponding methods:
template<typename K>
class EOne : public E<K>
{
public:
EOne() {}
EOne(const EOne& x) {...}
void init() override
{
...
}
void insert(const K& v) override
{
...
}
size_t count() const override
{
...
}
void copy(const E<K>& o) override
{
...
}
private:
// some private fields
};
and ETwo : public E<K>, which is similar to EOne. Also, there is a different class J, which has a member std::vector<E<K>> that needs to be instantiated during construction:
template<typename K>
class J
{
public:
J(size_t n, const E<K>& e) : v(n, e)
{}
private:
std::vector<E<K>> v;
}
In essence, by getting a constant reference for a E<K> object, I want J's constructor to use the reference to instantiate all n objects of v using e as a template (i.e., call the copy constructor). As you can imagine, my goal is to have e be an object of either EOne<K> or ETwo<K>. For instance, I would make a call to J<K>::J(size_t n, const E<K>& e) the following way:
int main(int argc, char** argv)
{
EOne<std::string> e;
J<std::string> j(10, e); // populate v with 10 copies of e
...
}
However, the above does not compile and the compiler complains that I cannot instantiate abstract class (I am using vc++ but I believe I will get the same error on other compilers as well). Therefore, my question has to do on how I can overcome this problem? Do you have any suggestions on how I can make my design more practical.
Thank you
There is more than one approach to this. What follows is the most complex reasonable one. It requires lots of work in the type definitions, but leads to the cleanest "client" code that uses these types.
It is time to learn how to make a type regular.
An instance of a regular type behaves like a value. C++ algorithms and container work far better with regular types than it does with abstract types.
template<class K>
class E_interface {
public:
virtual ~E_interface() {};
virtual void init() = 0;
virtual void insert(const K& k) = 0;
virtual size_t count() const = 0;
virtual void copy_from(const E_interface& x) = 0;
std::unique_ptr<E_interface> clone() const = 0;
};
this is basically your E, except I added clone().
template<class T, class D=std::default_delete<D>, class Base=std::unique_ptr<T>>
struct clone_ptr:Base {
using Base::Base;
clone_ptr(Base&& b):Base(std::move(b)) {}
clone_ptr()=default;
clone_ptr(clone_ptr&&o)=default;
clone_ptr(clone_ptr const& o):
clone_ptr(
o?clone_ptr(o->clone()):clone_ptr()
)
{}
clone_ptr& operator=(clone_ptr&&o)=default;
clone_ptr& operator=(clone_ptr const&o) {
if (*this && o) {
get()->copy_from(*o.get());
} else {
clone_ptr tmp(o);
*this = std::move(tmp);
}
return *this;
}
};
The clone_ptr is a smart pointer that is a unique_ptr that knows how to copy itself by calling clone() and copy_from on the stored object. It may have some typos.
Now we write our E:
template<class K>
class E {
clone_ptr<E_interface<K>> pImpl;
public:
E() = default;
E( std::unique_ptr<E_interface<K>> in ):pImpl(std::move(in)) {}
E( E const& )=default;
E( E && )=default;
E& operator=( E const& )=default;
E& operator=( E && )=default;
explicit operator bool() const { return (bool)pImpl; }
void init() { if (*this) pImpl->init(); }
void insert(const K& k) ( if (*this) pImpl->insert(k); }
size_t count() const { if (*this) pImpl->count(); else return 0; }
};
Our E<K> is now a value type. It can be stored in a vector, copied, moved, etc.
How do we do EOne and ETwo?
First, take your existing EOne and ETwo and call them EOne_impl and ETwo_impl. Implement a clone() function that does a return std::make_unique<EOne_impl>(*this); for EOne_impl and similar for ETwo_impl.
Then this helper:
template<class Impl, class K>
struct E_impl: E<K> {
using E<K>::E<K>;
E_impl() : E<K>( std::make_unique<Impl>() ) {}
template<class...Args>
E_impl(Args&&...args) : E<K>( std::make_unique<Impl>(std::forward<Args>(args)...) ) {}
};
gives us
template<class K>
using Eone = E_impl< Eone_impl, K >;
template<class K>
using Etwo = E_impl< Etwo_impl, K >;
and I believe your J and main code starts compiling and working as-is.
What we just did was create value-semantics E<K> type that contains a pImpl (pointer to implementation) pointing to a pure-virtual interface that knows how to copy itself, as well as the interface we want on an E<K>.
We then forwarded the interface of E<K> to the E_interface<K> for each method. We didn't expose copy_from or clone, as those become operator= and our copy constructor.
To implement E<K>, you first implement E_interface<K>. Then I wrote a helper to create a derived type from E<K> that implicitly uses that implementation.
Note that our E<K> is almost-never empty; not never-empty. This is more efficient and simpler, but can cause problems down the road.
E<K> becomes a polymorphic value-semantics type. This is a strange beast in some senses (as many languages don't support such a type), but in other senses it behaves exactly the way you'd want it to behave.
A similar solution in C# or Java would have the data stored in the vectors be fully garbage collected reference-semantics types, not value-semantics types.
This is similar to a std::vector<std::shared_ptr<E<K>> (with the note that shared pointers are not fully garbage collected). Also note that copies of the shared_ptr end up being pointing to the same object, not new copies of it.
A std::vector<value_ptr<E_interface<K>> would also be a reasonable solution and get rid of some of the gymnastics I did in my E<K> and E_impl<K>. In this case, you wouldn't rename E to E_interface. You'd initialize the vector with
J<std::string> j(10, std::make_unique<EOne<std::string>>(e))
or somesuch.
Part of your problem is you have to ask yourself "what does it mean to copy an E<K>". In C++ you get to answer this question yourself; depending on how you answer it, you may or may not be permitted to store it in a std::vector.
Since std::vector<E<K>> v; requires a static instantiation of class E, it will never compile (as you already noticed correctly). To make it work should use
std::vector<std::shared_ptr<E<K>>> v;
instead. It can store your objects EOne and ETwo dynamically while they can be referred with a pointed of type E. To add a new object to the vector you can use push_back:
v.push_back(std::make_shared<EOne<K>>{});
To cast between the types you can use dynamic and static cast functions for smart pointers e.g. std::dynamic_pointer_cast<>().

Is it possible to resolve static members similarly to overloading the member access operator for another type?

I am not sure what to call it, but is something like this possible as the commented out line reflects?
template <typename T>
class Test
{
public:
Test(T& t) : m_t(t) {}
T* operator->() { return &m_t; }
private:
T& m_t;
};
class A
{
public:
static const int integer = 0;
void function() {}
};
int main()
{
A a;
Test<A> test(a);
test->function();
// Something similar to doing Test<A>::integer?
return 0;
}
Well, why don't you do:
test->integer;
You can always access static members the same way as non-static ones (i.e. from an instance variable).
The other option would be to define in Test:
template <typename T>
class Test
{
public:
typedef T value_type;
// ...
};
In which case you will be able to do:
Test<A>::value_type::integer;
which will avoid the need of creating an instance of Test<A>.
At last, if you are using C++11 and Test follows the smart pointers conventions, then you will have:
std::pointer_traits<Test<A> >::element_type::integer;
which has the advantage to work even if you replace Test<A> with A*.
No. In C++, "overloading" only makes sense for functions. Instead of mixing static and non-static items in a class, you could try making two separate classes, both with all non-static members. Return your value from a function call, rather than using a public static member variable.

How can I have a container of template elements

I am trying to have a container of template elements but it's not compiling because the first argument is not given
So I want to put the following class in a std::map
template <typename T>
class TemplateParam
{
ITemplateParam<T> param_;
public:
TemplateParam(T value)
{
if (sizeof(value) >= sizeof(void*))
param_ = ptrTemplateParam<T>(value);
else
param_ = cpyTemplateParam<T>(value);
}
const T &getParam() const { return param_.getParam(); }
};
ITemplateParam
template <typename U>
class ITemplateParam
{
public:
virtual ~ITemplateParam(){}
virtual const U& getParam() const = 0;
};
I think I understand why I can't put elements of different sizes in a container, it's why I used ptrTemplateParam and cpyTemplateParam. (I have also tried with the shared_ptr)
Do you have any idea how can I resolve my problem
I can use boost library
I have looked at this link but I don't know how can I declare the getter.
Edit:
Thanks to your answer I am able to store it in a map but I'm not able to insert an element in the map and I have to use void*
So I have changed my class to:
class ITemplateParam
{
public:
virtual ~ITemplateParam(){}
virtual const void *getParam() const = 0;
};
template <typename U>
class ptrTemplateParam : public ITemplateParam
{
U param_;
public:
ptrTemplateParam(U & param) : param_(param) {}
virtual const void *getParam() const { return param_; }
};
class TemplateParam
{
std::shared_ptr<ITemplateParam> param_;
public:
template <typename T>
TemplateParam(T value): param_(ptrTemplateParam<T>(value))
{
}
const void *getParam() const { return param_->getParam();}
};
and I try to do
std::map<std::string, TemplateParam> m_;
m_["integer"] = TemplateParam(5);
Edit2
boost::any was the solution
If you need to have a container that contains elements of different type then you have
basically 3 ways:
Have container of variants or unions.
Have container of polymorphic pointers or polymorphic smart pointers.
Use intrusive container.
It is unclear from your question what would be best for you.
IMHO, if you want to put different items in the same container, you should consider using Boost.Variant. This is not a direct answer to your actual example here, but I found this pattern very useful for this category of problems. You avoid using pointers and enforcing inheritance in an elegant way.
class A {};
class B {};
typedef boost::variant<A, B> item_t;
...
vector<item_t> my_container;

How can I use covariant return types with smart pointers?

I have code like this:
class RetInterface {...}
class Ret1: public RetInterface {...}
class AInterface
{
public:
virtual boost::shared_ptr<RetInterface> get_r() const = 0;
...
};
class A1: public AInterface
{
public:
boost::shared_ptr<Ret1> get_r() const {...}
...
};
This code does not compile.
In visual studio it raises
C2555: overriding virtual function return type differs and is not
covariant
If I do not use boost::shared_ptr but return raw pointers, the code compiles (I understand this is due to covariant return types in C++). I can see the problem is because boost::shared_ptr of Ret1 is not derived from boost::shared_ptr of RetInterface. But I want to return boost::shared_ptr of Ret1 for use in other classes, else I must cast the returned value after the return.
Am I doing something wrong?
If not, why is the language like this - it should be extensible to handle conversion between smart pointers in this scenario? Is there a desirable workaround?
Firstly, this is indeed how it works in C++: the return type of a virtual function in a derived class must be the same as in the base class. There is the special exception that a function that returns a reference/pointer to some class X can be overridden by a function that returns a reference/pointer to a class that derives from X, but as you note this doesn't allow for smart pointers (such as shared_ptr), just for plain pointers.
If your interface RetInterface is sufficiently comprehensive, then you won't need to know the actual returned type in the calling code. In general it doesn't make sense anyway: the reason get_r is a virtual function in the first place is because you will be calling it through a pointer or reference to the base class AInterface, in which case you can't know what type the derived class would return. If you are calling this with an actual A1 reference, you can just create a separate get_r1 function in A1 that does what you need.
class A1: public AInterface
{
public:
boost::shared_ptr<RetInterface> get_r() const
{
return get_r1();
}
boost::shared_ptr<Ret1> get_r1() const {...}
...
};
Alternatively, you can use the visitor pattern or something like my Dynamic Double Dispatch technique to pass a callback in to the returned object which can then invoke the callback with the correct type.
There is a neat solution posted in this blog post (from Raoul Borges)
An excerpt of the bit prior to adding support for mulitple inheritance and abstract methods is:
template <typename Derived, typename Base>
class clone_inherit<Derived, Base> : public Base
{
public:
std::unique_ptr<Derived> clone() const
{
return std::unique_ptr<Derived>(static_cast<Derived *>(this->clone_impl()));
}
private:
virtual clone_inherit * clone_impl() const override
{
return new Derived(*this);
}
};
class concrete: public clone_inherit<concrete, cloneable>
{
};
int main()
{
std::unique_ptr<concrete> c = std::make_unique<concrete>();
std::unique_ptr<concrete> cc = c->clone();
cloneable * p = c.get();
std::unique_ptr<clonable> pp = p->clone();
}
I would encourage reading the full article. Its simply written and well explained.
You can't change return types (for non-pointer, non-reference return types) when overloading methods in C++. A1::get_r must return a boost::shared_ptr<RetInterface>.
Anthony Williams has a nice comprehensive answer.
What about this solution:
template<typename Derived, typename Base>
class SharedCovariant : public shared_ptr<Base>
{
public:
typedef Base BaseOf;
SharedCovariant(shared_ptr<Base> & container) :
shared_ptr<Base>(container)
{
}
shared_ptr<Derived> operator ->()
{
return boost::dynamic_pointer_cast<Derived>(*this);
}
};
e.g:
struct A {};
struct B : A {};
struct Test
{
shared_ptr<A> get() {return a_; }
shared_ptr<A> a_;
};
typedef SharedCovariant<B,A> SharedBFromA;
struct TestDerived : Test
{
SharedBFromA get() { return a_; }
};
Here is my attempt :
template<class T>
class Child : public T
{
public:
typedef T Parent;
};
template<typename _T>
class has_parent
{
private:
typedef char One;
typedef struct { char array[2]; } Two;
template<typename _C>
static One test(typename _C::Parent *);
template<typename _C>
static Two test(...);
public:
enum { value = (sizeof(test<_T>(nullptr)) == sizeof(One)) };
};
class A
{
public :
virtual void print() = 0;
};
class B : public Child<A>
{
public:
void print() override
{
printf("toto \n");
}
};
template<class T, bool hasParent = has_parent<T>::value>
class ICovariantSharedPtr;
template<class T>
class ICovariantSharedPtr<T, true> : public ICovariantSharedPtr<typename T::Parent>
{
public:
T * get() override = 0;
};
template<class T>
class ICovariantSharedPtr<T, false>
{
public:
virtual T * get() = 0;
};
template<class T>
class CovariantSharedPtr : public ICovariantSharedPtr<T>
{
public:
CovariantSharedPtr(){}
CovariantSharedPtr(std::shared_ptr<T> a_ptr) : m_ptr(std::move(a_ptr)){}
T * get() final
{
return m_ptr.get();
}
private:
std::shared_ptr<T> m_ptr;
};
And a little example :
class UseA
{
public:
virtual ICovariantSharedPtr<A> & GetPtr() = 0;
};
class UseB : public UseA
{
public:
CovariantSharedPtr<B> & GetPtr() final
{
return m_ptrB;
}
private:
CovariantSharedPtr<B> m_ptrB = std::make_shared<B>();
};
int _tmain(int argc, _TCHAR* argv[])
{
UseB b;
UseA & a = b;
a.GetPtr().get()->print();
}
Explanations :
This solution implies meta-progamming and to modify the classes used in covariant smart pointers.
The simple template struct Child is here to bind the type Parent and inheritance. Any class inheriting from Child<T> will inherit from T and define T as Parent. The classes used in covariant smart pointers needs this type to be defined.
The class has_parent is used to detect at compile time if a class defines the type Parent or not. This part is not mine, I used the same code as to detect if a method exists (see here)
As we want covariance with smart pointers, we want our smart pointers to mimic the existing class architecture. It's easier to explain how it works in the example.
When a CovariantSharedPtr<B> is defined, it inherits from ICovariantSharedPtr<B>, which is interpreted as ICovariantSharedPtr<B, has_parent<B>::value>. As B inherits from Child<A>, has_parent<B>::value is true, so ICovariantSharedPtr<B> is ICovariantSharedPtr<B, true> and inherits from ICovariantSharedPtr<B::Parent> which is ICovariantSharedPtr<A>. As A has no Parent defined, has_parent<A>::value is false, ICovariantSharedPtr<A> is ICovariantSharedPtr<A, false> and inherits from nothing.
The main point is as Binherits from A, we have ICovariantSharedPtr<B>inheriting from ICovariantSharedPtr<A>. So any method returning a pointer or a reference on ICovariantSharedPtr<A> can be overloaded by a method returning the same on ICovariantSharedPtr<B>.
Mr Fooz answered part 1 of your question. Part 2, it works this way because the compiler doesn't know if it will be calling AInterface::get_r or A1::get_r at compile time - it needs to know what return value it's going to get, so it insists on both methods returning the same type. This is part of the C++ specification.
For the workaround, if A1::get_r returns a pointer to RetInterface, the virtual methods in RetInterface will still work as expected, and the proper object will be deleted when the pointer is destroyed. There's no need for different return types.
maybe you could use an out parameter to get around "covariance with returned boost shared_ptrs.
void get_r_to(boost::shared_ptr<RetInterface>& ) ...
since I suspect a caller can drop in a more refined shared_ptr type as argument.