Передача значения родительских элементов данных дочернему классу

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