Здравствуйте.
Есть вот такие классы
class A()
{
public:
int arr[1000];
int foo;
void calc();
void calc_2();
void calc_3();
}
class B()
{
public:
int arr[1000];
char bar;
void calc();
void calc_2();
void calc_4();
}
Хочу объединить эти классы. Начитавшись статей в Интернете вижу вот такое решение:
class ISomeGeneralClass()
{
public:
virtual void calc();
virtual void calc_2();
}
class A(): public ISomeGeneralClass
{
public:
int arr[1000];
int foo;
virtual void calc() { /* Описание поведения А */ };
}
class B(): public ISomeGeneralClass
{
public:
int arr[1000];
char bar;
virtual void calc() { /* Описание поведения B */ };
}
Но меня смущает, что у обоих классов есть одинаковые поля данных int arr[1000]. Не нужно ли это поле вынести в отдельный класс от который будут использовать A и B? Вот что-то такое:
class ISomeGeneralClass()
{
public:
virtual void calc();
virtual void calc_2();
}
class Data
{
public:
int arr[1000];
}
class A(): public ISomeGeneralClass
{
public:
Data data;
int foo;
virtual void calc() { /* Описание поведения А */ };
}
class B(): public ISomeGeneralClass
{
public:
Data data;
char bar;
virtual void calc() { /* Описание поведения B */ };
}
Помогите, пожалуйста, решить этот вопрос.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте.
А>Есть вот такие классы
А если не дурить себе и людям голову преждевременным абстрагированием? Что это за calc, calc_2, etc... и зачем их объединять?
Может быть, тут нужно иерархию городить, а может, шаблоны.
Есть класс A() в программе foo и класс B() в программе bar. Сейчас классы — это просто обертка над кучей функций. Часть данных у этих двух классов совпадают, но есть и отличия. Аналогично с функциями — часть полностью одинакова, часть выполняют похожие действия с некоторыми отличиями. Хочу написать единую программу, так как действия обоих классов схожи и было бы логично иметь все в одном месте и для последующей поддержки будет проще менять что-то в коде одной программы.
class A()
{
public:
int arr[1000]; // это поле полностью совпадает с полем в классе B
int foo; // это уникальное поле данных для данного класса
// код этой функции полностью совпадает с кодом в классе B
void calc()
{
for (int i = 0; i < 1000; i++) arr[i] = i;
}
// У этой функции есть небольшие отличия от аналогичной в классе B
void calc_2()
{
std::cout << arr[0];
foo = 123 + arr[1];
std::cout << foo;
}
// Уникальная функция для класса А
void calc_3()
{
arr[3] = 0xFF;
}
}
class B()
{
public:
int arr[1000];
char bar;
void calc()
{
for (int i = 0; i < 1000; i++) arr[i] = i;
}
void calc_2()
{
std::cout << arr[0];
bar = 'A';
std::cout << bar;
}
// Уникальная функция для класса B
void calc_4()
{
arr[100] = 0xAA;
}
}
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте.
А>Есть вот такие классы
А>А>class A()
А>{
А>public:
А> int arr[1000];
А> int foo;
А> void calc();
А> void calc_2();
А> void calc_3();
А>}
А>class B()
А>{
А>public:
А> int arr[1000];
А> char bar;
А> void calc();
А> void calc_2();
А> void calc_4();
А>}
А>
А>Хочу объединить эти классы. Начитавшись статей в Интернете вижу вот такое решение:
А>А>class ISomeGeneralClass()
А>{
А>public:
А> virtual void calc();
А> virtual void calc_2();
А>}
А>class A(): public ISomeGeneralClass
А>{
А>public:
А> int arr[1000];
А> int foo;
А> virtual void calc() { /* Описание поведения А */ };
А>}
А>class B(): public ISomeGeneralClass
А>{
А>public:
А> int arr[1000];
А> char bar;
А> virtual void calc() { /* Описание поведения B */ };
А>}
А>
А>Но меня смущает, что у обоих классов есть одинаковые поля данных int arr[1000]. Не нужно ли это поле вынести в отдельный класс от который будут использовать A и B? Вот что-то такое:
А>А>class ISomeGeneralClass()
А>{
А>public:
А> virtual void calc();
А> virtual void calc_2();
А>}
А>class Data
А>{
А>public:
А> int arr[1000];
А>}
А>class A(): public ISomeGeneralClass
А>{
А>public:
А> Data data;
А> int foo;
А> virtual void calc() { /* Описание поведения А */ };
А>}
А>class B(): public ISomeGeneralClass
А>{
А>public:
А> Data data;
А> char bar;
А> virtual void calc() { /* Описание поведения B */ };
А>}
А>
А>Помогите, пожалуйста, решить этот вопрос.
Общее замечание: не должно быть никаких публичных данных. Вообще. Без никаких исключений.
Здравствуйте,
opener, Вы сами себе противоречите:
O>Общее замечание: не должно быть никаких публичных данных. Вообще. Без никаких исключений.
Здравствуйте, Stgl, Вы писали:
S>Есть класс A() в программе foo и класс B() в программе bar. Сейчас классы — это просто обертка над кучей функций. Часть данных у этих двух классов совпадают, но есть и отличия. Аналогично с функциями — часть полностью одинакова, часть выполняют похожие действия с некоторыми отличиями. Хочу написать единую программу, так как действия обоих классов схожи и было бы логично иметь все в одном месте и для последующей поддержки будет проще менять что-то в коде одной программы.
Если это обёртка над кучей функций, то было бы естественно выделить библиотечный базовый класс, который неизменен — не зависит от целей приложения.
После чего в каждом приложении выполнять настройку этой базы.
Настройку можно выполнять несколькими способами, по вкусу:
— наследники являются обёртками над обёрткой, т.е. это не ООП-наследование, а, скорее, паттерн Адаптер
— у базы есть точки кастомизации в виде виртуальных методов, наследники их переопределяют
— ... в виде членов-данных, возможно, функциональной природы (колбеки, указатели на интерфейсы и т.п.), — наследники снабжают базовый объект своими Стратегиями
— ... в виде параметров шаблона (база — шаблон класса), наследники указывают эти параметры, вплоть до использования идиомы CRTP
// У этой функции есть небольшие отличия от аналогичной в классе B
void calc_2()
Специально для этого есть паттерн Шаблонный Метод, суть которого в том, чтобы
void calc_2() { calc2_1(); calc2_2(); ..... } // общий план работ одинаковый, но
virtual void calc2_1(); // детали (пере)определяются в наследниках
virtual void calc2_2();
....
Если поведение варьируется только от программы к программе, т.е. в одной программе не могут сосуществовать оба класса,
то можно даже без шаблонов, — выполнить декомпозицию: вынести уникальные части во внешние классы и функции, и в разных программах определить их по-разному.
Фактически, это получается условная компиляция.