I've been looking around for a way to do this, and I'm not sure it's even possible. I've got a class in Java that takes an instance of a generically-typed interface as part of its constructor, and I'd like to recreate it in C++ (it's a utility class that is handy in many situations). To the best of my understanding, the closest equivalent to an interface in C++ is a pure virtual class, and the (somewhat) equivalent of generics is templates.
So let's say I have some classes defined as follows:
template<typename R>
class AnInterface
{
public:
virtual R run() = 0;
virtual ~AnInterface() {}
};
template<typename R>
class Processor
{
public:
Processor(std::vector<AnInterface<R>> toRun) : toRun(toRun) {}
std::vector<R> process() {
std::vector<R> res;
for(int i = 0; i < this->toRun.size(); ++i)
res.push_back(toRun[i].run());
return res;
}
private:
std::vector<AnInterface<R>> toRun;
};
class AnInstanceClass : public AnInterface<int>
{
int run() { return 1+1; }
};
I'd like to be able to do something like this with them:
int main()
{
std::vector<AnInterface<int>> toRun;
toRun.push_back(AnInstanceClass());
toRun.push_back(AnInstanceClass());
Processor<int> p(toRun);
std::vector<int> p.process();
}
Basically, have a class who's job is to take a list of objects, run them, and then return a list of their results, while being agnostic to the types of objects and results (assuming that the objects have a 'run' function). In Java, I accomplished this with generics and interfaces. I tried implementing the above solution in C++, but it doesn't compile and the compiler output is very cryptic, suggesting that I'm screwing up something very fundamental to the language. My C++ is a little rusty, so I'm not exactly sure what that is. How can something like this be implemented in C++?
Edit: Here's the error message when I try to compile the above code:
In file included from /usr/include/c++/4.8/vector:64:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_vector.h: In instantiation of ‘class std::vector<AnInterface<int> >’:
test.cpp:36:36: required from here
/usr/include/c++/4.8/bits/stl_vector.h:704:7: error: cannot allocate an object of abstract type ‘AnInterface<int>’
resize(size_type __new_size, value_type __x = value_type())
^
test.cpp:4:7: note: because the following virtual functions are pure within ‘AnInterface<int>’:
class AnInterface
^
test.cpp:7:19: note: R AnInterface<R>::run() [with R = int]
virtual R run() = 0;
^
test.cpp: In function ‘int main()’:
test.cpp:40:23: error: expected initializer before ‘.’ token
std::vector<int> p.process();
^
test.cpp: In instantiation of ‘Processor<R>::Processor(std::vector<AnInterface<R> >) [with R = int]’:
test.cpp:39:27: required from here
test.cpp:15:68: error: no matching function for call to ‘std::vector<int, std::allocator<int> >::vector(std::vector<AnInterface<int> >&)’
Processor(std::vector<AnInterface<R> > toRun) : toRun(toRun) {}
^
test.cpp:15:68: note: candidates are:
In file included from /usr/include/c++/4.8/vector:64:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_vector.h:398:9: note: template<class _InputIterator> std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&)
vector(_InputIterator __first, _InputIterator __last,
^
/usr/include/c++/4.8/bits/stl_vector.h:398:9: note: template argument deduction/substitution failed:
test.cpp:15:68: note: candidate expects 3 arguments, 1 provided
Processor(std::vector<AnInterface<R> > toRun) : toRun(toRun) {}
^
In file included from /usr/include/c++/4.8/vector:64:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_vector.h:310:7: note: std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = int; _Alloc = std::allocator<int>]
vector(const vector& __x)
^
/usr/include/c++/4.8/bits/stl_vector.h:310:7: note: no known conversion for argument 1 from ‘std::vector<AnInterface<int> >’ to ‘const std::vector<int, std::allocator<int> >&’
/usr/include/c++/4.8/bits/stl_vector.h:295:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
vector(size_type __n, const value_type& __value = value_type(),
^
/usr/include/c++/4.8/bits/stl_vector.h:295:7: note: no known conversion for argument 1 from ‘std::vector<AnInterface<int> >’ to ‘std::vector<int, std::allocator<int> >::size_type {aka long unsigned int}’
/usr/include/c++/4.8/bits/stl_vector.h:256:7: note: std::vector<_Tp, _Alloc>::vector(const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
vector(const allocator_type& __a)
^
/usr/include/c++/4.8/bits/stl_vector.h:256:7: note: no known conversion for argument 1 from ‘std::vector<AnInterface<int> >’ to ‘const allocator_type& {aka const std::allocator<int>&}’
/usr/include/c++/4.8/bits/stl_vector.h:248:7: note: std::vector<_Tp, _Alloc>::vector() [with _Tp = int; _Alloc = std::allocator<int>]
vector()
^
/usr/include/c++/4.8/bits/stl_vector.h:248:7: note: candidate expects 0 arguments, 1 provided
In file included from /usr/include/c++/4.8/vector:69:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/vector.tcc: In instantiation of ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vector<_Tp, _Alloc>::iterator, const _Tp&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<AnInterface<int>*, std::vector<AnInterface<int> > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = AnInterface<int>*]’:
/usr/include/c++/4.8/bits/stl_vector.h:913:28: required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; std::vector<_Tp, _Alloc>::value_type = AnInterface<int>]’
test.cpp:37:38: required from here
/usr/include/c++/4.8/bits/vector.tcc:329:19: error: cannot allocate an object of abstract type ‘AnInterface<int>’
_Tp __x_copy = __x;
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface
^
In file included from /usr/include/c++/4.8/vector:69:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/vector.tcc:329:8: error: cannot declare variable ‘__x_copy’ to be of abstract type ‘AnInterface<int>’
_Tp __x_copy = __x;
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface
^
In file included from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++allocator.h:33:0,
from /usr/include/c++/4.8/bits/allocator.h:46,
from /usr/include/c++/4.8/vector:61,
from test.cpp:1:
/usr/include/c++/4.8/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(__gnu_cxx::new_allocator<_Tp>::pointer, const _Tp&) [with _Tp = AnInterface<int>; __gnu_cxx::new_allocator<_Tp>::pointer = AnInterface<int>*]’:
/usr/include/c++/4.8/ext/alloc_traits.h:216:9: required from ‘static void __gnu_cxx::__alloc_traits<_Alloc>::construct(_Alloc&, __gnu_cxx::__alloc_traits<_Alloc>::pointer, const _Tp&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; __gnu_cxx::__alloc_traits<_Alloc>::pointer = AnInterface<int>*]’
/usr/include/c++/4.8/bits/stl_vector.h:906:34: required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >; std::vector<_Tp, _Alloc>::value_type = AnInterface<int>]’
test.cpp:37:38: required from here
/usr/include/c++/4.8/ext/new_allocator.h:130:9: error: cannot allocate an object of abstract type ‘AnInterface<int>’
{ ::new((void *)__p) _Tp(__val); }
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface
^
In file included from /usr/include/c++/4.8/vector:62:0,
from test.cpp:1:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, const _T2&) [with _T1 = AnInterface<int>; _T2 = AnInterface<int>]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:75:53: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const AnInterface<int>*, std::vector<AnInterface<int> > >; _ForwardIterator = AnInterface<int>*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const AnInterface<int>*, std::vector<AnInterface<int> > >; _ForwardIterator = AnInterface<int>*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const AnInterface<int>*, std::vector<AnInterface<int> > >; _ForwardIterator = AnInterface<int>*; _Tp = AnInterface<int>]’
/usr/include/c++/4.8/bits/stl_vector.h:316:32: required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = AnInterface<int>; _Alloc = std::allocator<AnInterface<int> >]’
test.cpp:39:27: required from here
/usr/include/c++/4.8/bits/stl_construct.h:83:7: error: cannot allocate an object of abstract type ‘AnInterface<int>’
::new(static_cast<void*>(__p)) _T1(__value);
^
test.cpp:4:7: note: since type ‘AnInterface<int>’ has pure virtual functions
class AnInterface