Допустим, я занимаюсь разработкой менеджера списка покупок.У меня есть окно с GroceryListDisplay
, которое представляет собой элемент управления, который отображает элементы, которые находятся в списке покупок.Данные о продуктах хранятся компонентом Model программы в классе GroceryStorage
.
Чтобы загрузить сохраненный файл в мою программу, компонент Model моей программы должен быть снова заполнен импортированными данными.из файла.Компонент View необходимо будет уведомить об этих новых данных, иначе графический интерфейс пользователя не будет обновлен, и пользователь не сможет увидеть импортированные данные.
Вот концепция, которую я придумал, чтобы упростить это.
/* A View class that represents a GUI control that displays the grocery list */
class GroceryListDisplay {
public:
void repopulateFromModel(GroceryStorage* gs) {
this->gs = gs;
/* Delete every list entry that was loaded into GUI */
this->clearList();
/* Import grocery list from the Model */
void (*itemAdder)(std::string) = addItemToList;
this->gs->sendGroceryItemsToGUI(addItemToList);
}
void addItemToList(std::string);
void clearList();
private:
GroceryStorage* gs;
}
/* A Model class that stores the grocery list */
class GroceryStorage {
public:
void sendGroceryItemsToGUI(void (*itemAdder)(std::string)) {
/* Sends all stored items to the GUI */
for (int i = 0; i < (int)this->groceryItems.size(); ++i)
itemAdder(this->groceryItems[i]);
}
private:
std::vector<std::string> groceryItems;
}
Когда пользователь дает указание графическому интерфейсу импортировать определенный файл, представление вызовет функцию в модели, которая загружает данные из данного файла.Затем вызывается функция repopulateFromModel
для получения обновленного графического интерфейса.
У меня возникают проблемы с использованием указателя функции для обратного вызова в GroceryStorage::sendGroceryItemsToGUI
, потому что в противном случае модель будет иметьзнать, какую функцию в представлении она должна вызывать, что будет нарушением принципа Модель / Представление.
Есть одна большая проблема с этим блоком кода.Если я использую эту концепцию в реальной жизни, я получаю ошибку компилятора, которая говорит что-то похожее на
error: аргумент типа 'void (GroceryListDisplay ::) (std :: string)' делаетне соответствует 'void (*) (std :: string)'
Компилятор просит меня жестко закодировать имя класса, из которого происходит указатель на функцию?Я не могу этого сделать, потому что это будет означать, что Model знает, какой класс View отвечает за обработку обратного вызова, что, опять же, будет нарушением Model / View.
Я неправильно понял, как работают указатели на функции?