#c #inheritance
#c #наследование
Вопрос:
Целью программы было создание сценариев моделирования корпусов громкоговорителей.
Таким образом, у меня есть класс speaker, который определяет динамик.
Приложение родительского класса, которое содержит общие параметры всех вложений.
Дочерний класс, который сам по себе обладает специальными свойствами.
Используя полиморфизм и наследование, я получил первую программу, которая работает отлично, но мне нужно каждый раз пересчитывать базовые свойства enclosure:
class speaker
{
}
class Enclosure
{
int m_boxHeight;
speaker * m_speakerBass;//...
public://some functions
}
class closedBox : public Enclosure
{
public:
closedbox(speaker amp;speakerbass):Enclosure(speakerbass)// some functions
protected:
int paramclosed1;//...
}
int main()
{
speaker speakerbass;
cout <<endl<< "Please choose in the available enclosure proposals" << endl;
cout << "1 Closed box enclosure" << endl;
// cout << "2 Bass reflex enclosure" << endl;
// cout << "3 and so on..." << endl;
int choice;
cin>>choice;
switch (choice)
{
case 1:
closedbox * ClBox2Simu;
ClBox2Simu= new closedbox(speakerbass);
delete ClBox2Simu;
break;
case 2:
//... same but with bassreflex class child
break;
default:
cout<<"Then good bye";
}
return 0;
}
В случае моей программы данные-члены родительского класса могут быть переданы дочернему классу . Я имею в виду, что размерность блока Enclosure
одинакова в каждом дочернем классе bassreflex
или closedbox
.
Таким образом, я бы сейчас, если есть способ:
- создайте родительский класс
- выполните первые начальные общие вычисления
- создание дочерних элементов с родительскими параметрами (проблема)
Что означает в основном дочерний элемент = родительский элемент, что запрещено. В идее этого кода:
class speaker
{
public: // some functions
protected:
int fs;
int paramSpeaker2; //...
}
class Enclosure
{
public: //some common function
protected:
int m_boxHeight;
speaker *m_speakerBass //...
}
class closedBox : public Enclosure
{
public:
closedbox(); // some functions
protected:
int paramclosed1; //...
}
class bassreflex : public Enclosure
{
public:
bassreflex(); // some functions
protected:
int paramclosed1; //...
}
int main()
{
Enclosure initialBox;// calculate dimension,choose speaker...
closedbox * ClBox2Simu;
ClBox2Simu= initialBox;// child= parent which is forbidden
//do stuff concerning closedbox
delete ClBox2Simu;
bassreflex * BassReflex2Simu;
BassReflex2Simu= initialBox; //forbidden
//do stuff concerning bassreflex
delete BassReflex2Simu;
//... and so on for other child class using enclosure
delete initialBox
return 0;
}
Надеюсь, это понятно!
Комментарии:
1. Почему вы не инициализируете дочерний класс напрямую? Время для чтения конструкторов и списков инициализаторов элементов
2. Я не понимаю, где (или почему) вы «пересчитываете базовые свойства»?
3. Динамическое распределение в вашем первом примере совершенно не нужно.
4. @Danh,@UnholySheep Это то, что я делаю в первой программе, во второй я хочу вычислить общее свойство, например:
Enclosure commonEnclosure
затем объявить дочерние классыclosedbox box1
bassreflex box2
с параметрами родительскогоcommonEnclosure
класса .5. @Boulgour вы можете выполнить эту обычную инициализацию в базовом конструкторе, верно?
Ответ №1:
Симптомы, которые вы описываете, предполагают типичную проблему is-a и has-a, то есть проблему наследования и композиции.
В C принцип заключается в создании дочерних объектов. Процесс построения дочернего класса:
- сначала создается вложенный родительский объект
- затем создаются элементы дочернего класса
- и, наконец, тело дочернего конструктора выполняется для завершения построения.
Как только у вас возникают проблемы с этой логикой, это говорит о том, что наследование, вероятно, не лучший подход. Обычный совет в ООП — предпочесть композицию наследованию. Наследование в принципе должно использоваться только в том случае, если природа объекта не меняется.
Поскольку я не знаком с вашим доменом, вот типичный и более знакомый пример:
class animal {};
class cat : public animal {}; // ok: a cat will always remain an animal
class person {};
class employee : public person {}; // bad idea: a person could have several job
// or change job or (hopefully temporarily) without job
// possible alternative
class job_t { string title, company; date from,to; ... };
class person { vector<job_t> jobs; ... }; // very flexible
В вашем случае я бы понял, что Enclosure
у этого есть некоторые общие параметры, но есть фактор формы (я бы назвал это семейство), который определяет, как волны передаются в среду, и некоторые другие функции.
В этом случае вы могли бы пойти на:
class EnclosureFamily {
public:
double compute_volume_in_room() = 0; // abstract;
};
class Enclosure
{
public: //some common function
double compute_volume_in_room() {
return f->compute_volume_in_room(); // forwarding
}
protected:
int m_boxHeight;
speaker *m_speakerBass;
EnclosureFamily *f; // ok, but smart ponters should be preferred
};
class BoxEnclosure : public EnclosureFamily {
public:
double compute_volume_in_room() { ... };
};
Это позволяет вам изменять семейство вложений по своему усмотрению. Кстати, это реализация шаблона стратегии.
Если вам действительно нужно сохранить свой оригинальный дизайн, вы можете перезаписать родительский класс, используя приведение к родительскому классу и используя эффект нарезки:
*static_cast<Enclosure*>(BassReflex2Simu)= initialBox; // not forbidden but slicing
Однако я бы не советовал идти этим путем (имейте в виду, что сначала для этого потребуется надлежащее выполнение правила 3 для родительского)
Комментарии:
1. Хорошо, так что это возможно, но не универсально, мне нужно добавить в каждый подкласс указатель на общие параметры, поэтому, если однажды я добавлю общий параметр в родительский, мне нужно будет вручную обновить весь дочерний класс. Спасибо!