Reputation: 293
I'm trying to implement the strategy pattern in C++, and I'm having trouble figuring out the correct syntax. Here's a (rather trivial) java code example of what I'd like to do:
public static interface Processor<T> {
public void process(T toProcess);
}
public static class Printer implements Processor<String> {
@Override
public void process(String toProcess) {
System.out.println(toProcess);
}
}
public static class StringHandler {
public void handleData(Processor<String> processor) {
processor.process("Hello World!");
}
}
public static void main(String... args) throws Exception {
new StringHandler().handleData(new Printer());
}
Attempt at a C++ Equivalent:
#include <string>
using namespace std;
template <typename T>class Processor {
public:
virtual void process(T rhs) = 0;
};
class Printer : public Processor<string*> {
public:
void process(string* a) {
printf("string = %s\n", a->c_str());
}
};
class StringHandler {
public:
void handleData(Processor<string*> processor) {
string hello = "Hello World!!";
processor.process(&hello);
}
};
int main(int argc, char** argv) {
StringHandler h;
Printer p;
h.handleData(p);
}
When I attempt to compile the code, I get the following error:
Undefined symbols for architecture x86_64:
"Processor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>::process(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)", referenced from:
StringHandler::handleData(Processor<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>) in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Any insights regarding why my C++ code won't compile, or how to implement this template pattern in C++, would be greatly appreciated. A solution that compiles with C++98 would be preferable, though I am also interested in an approach that uses Functional libraries.
Upvotes: 1
Views: 892
Reputation: 490663
You're trying to pass a Processor
by value instead of reference, which would require instantiating Processor
(which isn't possible because it's an abstract class).
You can fix that by passing it by reference instead:
void handleData(Processor<string*> &processor) {
// ...
That said, your approach looks to me a lot like you're still basically writing Java (with a little C thrown in for bad measure), and just changing the syntax enough to get a C++ compiler to accept it.
In C++, the strategy pattern will usually be implemented as a template parameter. I'd probably write the code more like this:
struct print {
void operator()(std::string const &s) const {
std::cout << "string = " << s << "\n";
}
};
template <class Process>
void handle(Process p) {
p("Hello World!!");
};
int main() {
handle(print());
}
Note, however, that in many cases the strategy part is used in only one place, in which case it can make sense to define it as a lambda expression:
handle([](std::string const &s) { std::cout << "string = " << s << "\n"; });
Upvotes: 6
Reputation: 303890
The issue is how you declared handleData
:
void handleData(Processor<string*> processor) {
Processor<T>
is an abstract class. It cannot be constructed. If you could, you would slice the derived part of the object, which is where the actual implementation for process(T )
lives. gcc gives a much clearer error for me:
error: cannot declare parameter
processor
to be of abstract typeProcessor<std::basic_string<char>*>
You need to instead take your processor
by reference:
void handleData(Processor<string*>& processor) {
Upvotes: 5