Если вам нужно a void*
в вашей программе, ваш дизайн сломан! Есть несколько причин, чтобы по-прежнему использовать void*
, но все они действительны только в том случае, если вам приходится иметь дело со старыми интерфейсами библиотеки в стиле c. Если вы пишете свои собственные функции, всегда неправильно использовать void*
без каких-либо исключений.
Итак, в основном я пишу приложение GUI с разными объектами, которые появляются в окне .
Это именно то решение, которое у вас должно быть! Объекты должны представлять сами . Это означает: не пишите код, который "знает" что-то об объекте. Если вы сделаете это, сведения о классе или структуре будут не только в структуре / классе, но и в коде, который имеет дело с этими объектами этого класса / структуры. Это нарушенный дизайн и полная противоположность OOP.
Типичное решение - иметь другой класс, который может использовать общий интерфейс и что-то делать с элементами объектов. Класс должен предоставить некоторую информацию, какие элементы для обработки, а объект-обработчик знает , что делать. Итак, вы разделяете код на две части, одна знает, какие данные обрабатывать, а другая знает, что делать.
В вашем случае вы хотите иметь своего рода «редактор», поэтому давайте попробуем написать минимальный пример редактора. Я не предоставил ничего gui, так как это позволяет увеличить размер кода здесь!
Существует довольно распространенный паттерн, который мы называем сериализатором . Основная функциональность c состоит в том, чтобы позволить самим объектам «какие элементы» обрабатывать информацию (функция Serialize
) и классам / объектам-обработчикам, которые выполняют эту работу EditSerializer
и PrintSerializer
.
Теперь вам просто нужно предоставить объекты-обработчики для объектов, которые должны обрабатываться.
Полный пример:
struct Properties1
{
std::string name;
int size;
template < typename Serializer >
void Serialize( Serializer& ser )
{
// Here we only provide the "information" which data we have.
// at this line of code, we have no idea what a *serializer*
// will do with our data.
ser & name & size;
}
};
struct Properties2
{
std::string name1, name2;
int size1, size2;
template < typename Serializer >
void Serialize( Serializer& ser )
{
ser & name1 & name2 & size1 & size2;
}
};
struct EditSerializer
{
// Here we don't know which elements we get, but we know
// what we want to do with all of them!
// Print them and lets the user enter a new value
template < typename E >
EditSerializer& operator &( E& element )
{
std::cout << "Old value:" << element << std::endl;
std::cout << "Please enter new value " << std::endl;
std::cin >> element;
return *this;
}
};
struct PrintSerializer
{
template < typename E >
PrintSerializer& operator &( E& element )
{
std::cout << "Value" << element << std::endl;
return *this;
}
};
int main()
{
Properties1 p1{"Hallo",100};
Properties2 p2{"Another","Example",987,456};
EditSerializer eser;
p1.Serialize( eser );
p2.Serialize( eser );
PrintSerializer pser;
p1.Serialize( pser );
p2.Serialize( pser );
}
Теперь вы можете заменить классы сериализатора также на свои gui составные части. Вы также можете предоставить дополнительные теги в своих классах данных, которые могут предоставлять имена или редактировать позиции полей или что угодно, что вам нужно.
Помните: общая идея OOP состоит в том, чтобы хранить всю информацию в одном месте. Поэтому, если вы сохраните свой код позже, все изменения go будут только в одном месте, а весь другой код полностью не затронут этим изменением.
Код использует operator &
, чтобы писать код более умным, поскольку мы используем вызов функции. То, что мы используем &
, довольно часто встречается в шаблоне сериализатор . Но вы можете использовать любой оператор, который вам нравится, и даже прямой вызов функции. Использование оператора - это удобная функция.