Я пытаюсь улучшить существующий код C ++, удалив дублирующийся код, но не могу найти убедительного способа сделать это. Любое мнение от более опытных коллег по C ++ высоко ценится.
Итак, у меня есть два определения структуры, которые я не могу контролировать:
struct struct_1
{
...
other_s * s1;
other_s * s2;
other_s * s3;
... //other fields
};
struct struct_2
{
...
other_s * s1;
other_s * s2;
other_s * s3;
... //other fields, different than struct_1, but not that important
};
И наконец код, который я хочу улучшить. У меня есть два почти идентичных класса, которые одинаково работают с полями структуры с одинаковыми именами, но поля происходят из разных структур. Классы не работают с полями структуры, которые будут присутствовать только в одной структуре. Вот оно (упрощение):
class class_1
{
struct_1 * s;
class_1(){
s = new struct_1(); //the only practical difference
...
}
void method()
{
...
//this is simplification, in reality the code is more complex
//however the same as in class_2
inner_data += s->s1;
inner_data += s->s2;
inner_data += s->s3;
...
}
//other methods
};
class class_2
{
struct_2 * s;
class_2(){
s = new struct_2(); //the only practical difference
...
}
void method()
{
...
//this is simplification, in reality the code is more complex
//however the same as in class_1
inner_data += s->s1;
inner_data += s->s2;
inner_data += s->s3;
...
}
//other methods
};
Я потратил некоторое время, пытаясь его переделать, но ничего не получилось. Мой подход состоял в том, чтобы использовать только один класс class_1, но я не мог избежать проблем с доступом к struct_1 и struct_2 без множества if, разбросанных по всему.
Спасибо за помощь!
C ++ имеет шаблоны для этого:
template<typename T>
class MyClass
{
T* s;
MyClass(){
s = new T(); //the only practical difference
...
}
void method()
{
...
//this is simplification, in reality the code is more complex
//however the same as in class_2
inner_data += s->s1;
inner_data += s->s2;
inner_data += s->s3;
...
}
//other methods
};
Теперь вы можете использовать ваши классы как:
MyClass<struct_1> a;
а также
MyClass<struct_2> b;
и компилятор сгенерирует определения для этих классов на основе вашего шаблона.
Не забудьте освободить память в своем деструкторе!
Вы ищете шаблон:
template <typename S>
class C {
S * s;
C() s(new S()) {}
void method() {
// This is all fine as long as `S` has these members
inner_data += s->s1;
inner_data += s->s2;
inner_data += s->s3;
}
};
Тогда ваши занятия могут быть специализациями этого:
typedef C<struct_1> class_1;
typedef C<struct_2> class_2;
(И, надеюсь, ваш реальный код следует Правило трех, так как он возится с низкоуровневым распределением памяти.)
Шаблоны будут работать для этого, но если структуры в основном идентичны (например, если struct_2 просто добавляет больше полей в struct_1), вы, вероятно, можете превратить struct_1 в базовый класс и struct_2 в класс, производный от него (только добавляя новые члены данных) ,
В качестве альтернативы, вы также можете просто объединить все элементы данных в struct_1 (опять же, если предположить, что элементы данных в основном одинаковы с struct_s, просто добавив еще несколько) и добавить флаг или тип, указывающий, какие члены являются действительными.