2015-05-07 6 views
1

Я пытаюсь реализовать шаблон стратегии в C++, и мне трудно понять правильный синтаксис. Вот (довольно тривиально) ява код пример того, что я хотел бы сделать:Шаблон стратегии в C++ с generics

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()); 
} 

попытка C++ Эквивалент:

#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); 
} 

При попытке компиляции кода, я получаю следующее ошибка:

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) 

Любые идеи относительно того, почему мой C++ код не будет компилироваться, или как реализовать этот шаблон шаблона в C++, было бы весьма признателен. Решение, которое компилируется с C++ 98, было бы предпочтительным, хотя меня также интересует подход, в котором используются функциональные библиотеки.

+1

Не связанный с вашей проблемой, использование указателей в качестве параметров является смутно редкими, поэтому многие функции C++ принимают ссылки. 'printf' редко встречается на C++, чаще вы видите' std :: cout'. Когда у вас есть «интерфейс», вы почти всегда хотите дать ему «виртуальный» деструктор с определением, которое ничего не делает (но должно существовать!) –

+0

Ответ Барри верен. Но я также предлагаю опасаться вашего подхода здесь. Эта картина возникает очень редко и не имеет большого смысла, пока у вас не возникнет проблема. – QuestionC

ответ

6

Вы пытаетесь пропускать Processor по значению вместо ссылки, что потребует экземпляр Processor (что невозможно, потому что это абстрактный класс).

Вы можете исправить, передав его по ссылке, а:

void handleData(Processor<string*> &processor) { 
    // ... 

Тем не менее, ваш подход выглядит для меня очень много, как вы по-прежнему в основном пишу Java (с небольшим количеством С добавленными для плохой меры) и достаточно просто изменить синтаксис, чтобы заставить компилятор C++ принять его.

В C++ шаблон стратегии обычно реализуется как параметр шаблона. Я бы, наверное, написать код больше, как это:

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()); 
} 

Примечание, однако, что во многих случаях стратегия часть используется только в одном месте, в этом случае может иметь смысл определить его как лямбда-выражения :

handle([](std::string const &s) { std::cout << "string = " << s << "\n"; }); 
5

Вопрос заключается в том, как вы объявили handleData:

void handleData(Processor<string*> processor) { 

Processor<T> является абстрактным классом. Он не может быть построен. Если бы вы могли, вы бы получили slice производную часть объекта, в которой живет фактическая реализация для process(T). НКУ дает более четкую ошибку для меня:

error: cannot declare parameter processor to be of abstract type Processor<std::basic_string<char>*>

Вы должны вместо этого взять processor по ссылке:

void handleData(Processor<string*>& processor) { 
Смежные вопросы