C ++, имеющий дело с множественными перегрузками конструктора и избыточным кодом - PullRequest
0 голосов
/ 27 мая 2018

Я недавно проявил интерес к (пере) обучению программированию, поэтому я взялся за C ++, поскольку это широко используемый язык.Однако я наткнулся на контрольно-пропускной пункт и сомневаюсь, что мое решение - лучший способ обойти это.У меня относительно сложный класс (для меня в любом случае), с примерно 20 переменными, которые для упрощения были разделены на 4 группы.У него также есть родительский класс, который вызывается во время инициализации объекта.

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

Является ли это оптимальным способом?решения этой проблемы?Я также думал о том, чтобы сгруппировать эти переменные в классы или структуры, но кажется, что это излишне сложно, когда вызов соответствующих функций во время различных перегрузок конструктора должен помочь.Если это не оптимально, что будет лучшим способом решения этой проблемы?И почему?

Я могу предоставить более подробное описание моей проблемы, но это будет довольно большая стена текста (я сначала написал ее, но она слишком вышла из-под контроля),Заранее благодарим вас за ваш вклад.

По запросу, вот определение класса (Оружие).Родительский класс (Item) уже определен и работает как задумано, поэтому я не буду его вставлять, поэтому людям не придется читать массивную стену текста.

Определение класса оружия:

class Weapon: public Item {


public:


    // Default constructor
    Weapon();

    // Full constructor
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short CooldownType, double CooldownDuration, unsigned short CooldownShot, double CooldownPeriod, unsigned short ReloadType, unsigned short ReloadStyle, double ReloadTime, unsigned short MaxMagazine, unsigned short MaxAmmunition, unsigned short StartEnergy, unsigned short MaxEnergy);

    // Constructor for Weapons without Cooldown System
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short ReloadType, unsigned short ReloadStyle, double ReloadTime, unsigned short MaxMagazine, unsigned short MaxAmmunition, unsigned short CurrentEnergy, unsigned short MaxEnergy);

    // Constructor for Weapons without Reload System
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short CooldownType, double CooldownDuration, unsigned short CooldownShot, double CooldownPeriod, unsigned short MaxMagazine, unsigned short MaxAmmunition, unsigned short CurrentEnergy, unsigned short MaxEnergy);

    // Constuctor for Weapons without Energy System
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short CooldownType, double CooldownDuration, unsigned short CooldownShot, double CooldownPeriod, unsigned short ReloadType, unsigned short ReloadStyle, double ReloadTime, unsigned short MaxMagazine, unsigned short MaxAmmunition);

    // Constructor for Weapons without Cooldown nor Reload System
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short MaxMagazine, unsigned short MaxAmmunition, unsigned short CurrentEnergy, unsigned short MaxEnergy);

    // Constructor for Weapons without Cooldown nor Energy System
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short ReloadType, unsigned short ReloadStyle, double ReloadTime, unsigned short MaxMagazine, unsigned short MaxAmmunition);

    // Constructor for Weapons without Reload nor Energy System
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short CooldownType, double CooldownDuration, unsigned short CooldownShot, double CooldownPeriod, unsigned short MaxMagazine, unsigned short MaxAmmunition);

    // Constructor for Weapons without Cooldown, Reload nor Energy System
    Weapon(unsigned GenericID, bool NameFlag, double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short maxMagazine, unsigned short MaxAmmunition);

    ~Weapon();
    void m_print();

    /*Edited public get and set functions for each variable as they are not relevant*/



private:


    // Ubiquitous variables
    unsigned short WepGenericID = 0;
    unsigned short WepVariantID = 0;
    unsigned short WepSkinID = 0;

    double EquipLoad = 0;
    double EquipLoadperAmmo = 0;

    unsigned short ModesNo = 1;
    Mode* pModes = NULL;

    unsigned short MaxAmmunition = 0;
    unsigned short CurrentAmmunition = 0;

    unsigned short MaxMagazine = 0;
    unsigned short CurrentMagazine = 0;


    // Cooldown System variables
    bool WeaponCooldown = false;
    unsigned short CooldownType = 0;
    double CooldownDuration = 0;
    unsigned short CooldownAction = 0;
    double CooldownPeriod = 0;


    // Reload System variables
    unsigned short ReloadType = 0;
    unsigned short ReloadStyle = 0;
    double ReloadTime = 0;


    // Energy System variables
    unsigned short CurrentEnergy = 0;
    unsigned short MaxEnergy = 0;


    //Constructor Auxiliary Functions
    void m_setGeneralWeapon(double EquipLoad, double EquipLoadperAmmo, unsigned short ModesNo, Mode* pModes, unsigned short MaxMagazine, unsigned short MaxAmmunition);
    void m_setCooldownSystem(unsigned short CooldownType, double CooldownDuration, unsigned short CooldownAction, double CooldownPeriod);
    void m_setReloadSystem(unsigned short ReloadType, unsigned short ReloadStyle, double ReloadTime);
    void m_setEnergySystem(unsigned short StartEnergy, unsigned short MaxEnergy);
    void m_setWeaponIDs();
    void m_WepNameDecisionTree();
    string m_searchName();

};

Определение родительского класса элемента

class Item {


public:

    Item();
    Item(unsigned GenericID);
    Item(unsigned GenericID, bool NameFlag);
    ~Item();
    void m_setCustomName();


private:

    unsigned GenericID = 0;
    unsigned short GenCategoryID = 0;
    unsigned short GenSubCategoryID = 0;

    bool NameFlag = false;
    string ItemName = "Missingno";

    unsigned long InstanceID = 0;

};

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Одна проблема, с которой я столкнулся с API Weapon в опубликованном виде, заключается в том, что конструкторы принимают lot аргументов со свободной типизацией, что делает код, который использует их, трудным для понимания и проверки.Например, скажем, вы (или ваш коллега-разработчик) использовали API вашего конструктора для добавления этой строки в вашу кодовую базу:

Weapon bfg(id, true, 3.0, 5.0, 6, modesPtr, COOLDOWN_QUICK, 5.0, 3, 4, RELOAD_SLOW, RELOAD_ANYTIME, 3.8, 12, 14);

Читая эту строку, очень трудно понять, что означает большинство чисел.Если аргумент был случайно пропущен или порядок двух аргументов был изменен, вероятно, не будет очевидно (ни вам, ни компилятору), что там есть ошибка;вместо этого вы можете не узнать об ошибке до тех пор, пока какой-нибудь игровой тестер (или клиент?) не отправит отчет об ошибке, который является дорогим и трудоемким способом обнаружения ошибок.

Поэтому я рекомендую уменьшить количествоаргументов, которые вы должны передать конструктору как можно меньше.Например, другой способ написания вышеупомянутого может быть таким:

Weapon bfg(id, true);
bfg.SetEquipLoad(3.0);
bfg.SetEquipLoadPerAmmo(5.0);
bfg.SetModes(6, modesPtr);
bfg.SetCooldownType(COOLDOWN_QUICK);
[...]

По общему признанию, это намного более многословно (и это позволяет забыть установить то, что вы должны были установить), но по крайней мере, когдаЕсли вы посмотрите на это, то совершенно очевидно, что 3.0 применяется к настройке EquipLoad, а 5.0 применяется к настройке EquipLoadPerAmmo, а не наоборот.то есть вам не нужно постоянно смотреть назад и вперед между вашим файлом .h и кодом, чтобы попытаться выяснить, на что ссылается каждое значение.

Обратите внимание, что каждый метод set должен принимать все параметрынеобходимо дать полезный результат;так, например, если нет смысла указывать EquipLoad без указания EquipLoadPerAmmo, то вместо этого вы могли бы установить оба из них одним вызовом:

bfg.SetEquipLoadAndEquipLoadPerAmmo(3.0, 5.0);

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

Что касается обработки многословности для минимизации избыточного кода, то следующеешаг будет заключаться в том, чтобы обернуть вышеупомянутый код в функцию, чтобы для любого данного типа оружия было только одно место, которое его создает, например:

Weapon MakeBFG(unsigned id)
{
   Weapon bfg(id, true);
   bfg.SetEquipLoad(3.0);
   bfg.SetEquipLoadPerAmmo(5.0);
   bfg.SetModes(6, modesPtr);
   bfg.SetCooldownType(COOLDOWN_QUICK);
   [...]
   return bfg;
}

Теперь остальная часть вашего кода может просто вызвать Weapon bfg = MakeBFG(idCounter++); всякий раз, когда он хочет создать новое оружие BFG.

Помимо этого, я согласен с другим постером - ваш класс, кажется, обрабатывает множество разных вещей, и если вы можете найти способразложить его на несколько меньших классов (не все из которых должны быть доступны через публичный API; частные классы хороши), что, вероятно, поможет вам управлять общей сложностьюкод;это особенно полезно, если вы считаете, что хотите продолжать добавлять новые функции / поведения в будущем, поскольку, если вы соберете все вместе в одном классе, сложность этого класса быстро выйдет из-под контроля, когда вы попытаетесьон поддерживает все больше и больше различных вариантов поведения / вариантов использования.

0 голосов
/ 27 мая 2018

создайте отдельные классы для ваших подсистем.

создайте свое оружие, используя шаблон строителя / фабрики:

Вы также можете отделить боеприпасы, оставив лишь несколько реальных членов.Таким образом, вы можете построить все с помощью более модульного подхода, что даст вам возможность легче расширять или изменять свою функциональность

...