Как объединить два класса с практически одинаковым кодом, но работать на разных структурах

Я пытаюсь улучшить существующий код 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, разбросанных по всему.
Спасибо за помощь!

2

Решение

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;

и компилятор сгенерирует определения для этих классов на основе вашего шаблона.

Не забудьте освободить память в своем деструкторе!

5

Другие решения

Вы ищете шаблон:

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;

(И, надеюсь, ваш реальный код следует Правило трех, так как он возится с низкоуровневым распределением памяти.)

2

Шаблоны будут работать для этого, но если структуры в основном идентичны (например, если struct_2 просто добавляет больше полей в struct_1), вы, вероятно, можете превратить struct_1 в базовый класс и struct_2 в класс, производный от него (только добавляя новые члены данных) ,

В качестве альтернативы, вы также можете просто объединить все элементы данных в struct_1 (опять же, если предположить, что элементы данных в основном одинаковы с struct_s, просто добавив еще несколько) и добавить флаг или тип, указывающий, какие члены являются действительными.

0