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

У меня есть задание объявить класс Pet, класс Dog, класс Fish и класс Bird. У разных питомцев одинаковые методы, но некоторые характеристики разные. Я не хотел писать одно и то же три раза, только с тремя разными статистиками каждый раз.

Поэтому я научил меня создавать класс Pet, я создаю файл шаблона, который требует название вида и характеристики, используя директиву define препроцессора. Но я получаю эту ошибку во время компиляции:

C2100 — недопустимое косвенное обращение ProjectName c: \ program files (x86) \ microsoft visual studio \ 2017 \ enterprise \ vc \ tools \ msvc \ 14.12.25827 \ include \ xtree 1146

У меня есть следующие файлы:

Pet.h

#pragma once
#include <string>
#include <map>
class Pet {
protected:
std::string Name;
unsigned int Vim;
unsigned int PositiveEffectSize;
std::map<int, unsigned int> NegativeEffectsSize;
public:
enum EffectSize { small, big };
Pet(std::string name, unsigned int vim);
Pet() {};
std::string GetName() const;
unsigned int GetVim() const;
void InflictPositiveEffect();
void InflictNegativeEffect(EffectSize effectSize);
};

PetInstanceTemplate.h

#include "Pet.h"#ifndef _SpeciesName
#error "SpeciesNotDefined"#endif

class _SpeciesName : Pet {
protected:
unsigned int PositiveEffectSize = _PositiveEffectSize;
std::map<int, unsigned int> NegativeEffectsSize;
public:
_SpeciesName(std::string name, unsigned int vim) : Pet(name, vim) {
this->NegativeEffectsSize.insert(0, _NegativeEffectSizeSmall);
this->NegativeEffectsSize.insert(1, _NegativeEffectSizeBig);
}
_SpeciesName() {};
};

Dog.h, но файл заголовка других домашних животных похож

#pragma once

#undef _SpeciesName
#undef _PositiveEffectSize
#undef _NegativeEffectSizeSmall
#undef _NegativeEffectSizeBig
#define _SpeciesName Dog
#define _PositiveEffectSize 3
#define _NegativeEffectSizeSmall 0
#define _NegativeEffectSizeBig 10

#include "PetInstanceTemplate.h"

Есть ли способ заставить его работать таким образом? И каковы другие методы уменьшения избыточности определения класса?

Заранее спасибо 🙂

-2

Решение

Вы бы не получили много, если бы все методы остались прежними, но вы могли бы использовать списки инициализации и обращаться ко всему через Pet *

class Pet {
public: //Pet's constructor can be protected, if you only want derived classes to create them
Pet(std::string initName="", std::string initSound="", std::string initCoat="");
virtual ~Pet(){} //Only needed if deleting derived class through Pet*
std::string getName(){ return name; }
private:
std::string name;
std::string sound;
std::string coat;
};

class Bird : public Pet {
public:
Bird();
~Bird() override {}  //Overrides virtual ~Pet, if used
private:
int wingSpan;
};

Тогда в реализации:

Pet::Pet(std::string initName, std::string initSound, std::string initCoat)
: name(initName), sound(initSound), coat(initCoat){}

Bird::Bird()
: Pet::Pet("Bird","Chirp","Feathers"), wingSpan(6){}
0

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

Я понял, что то, что я хотел сделать, не имеет большого смысла. Поэтому я согласился на это:
я удалил unsigned int PositiveEffectSize а также std::map<int, unsigned int> NegativeEffectSizes из производного класса, если честно, я не знаю, зачем я его туда поместил … Я изменил конструктор класса Pet, поэтому мой конструктор производного класса просто вызывал конструктор базового класса.

Pet.h

#pragma once
#include <string>
#include <map>
class Pet {
protected:
std::string Name;
unsigned int Vim;
unsigned int PositiveEffectSize;
std::map<int, unsigned int> NegativeEffectsSize;
public:
static enum EffectSize { Small, Big };
Pet(std::string& name, unsigned int vim, unsigned int positiveEffectSize, unsigned int negativeEffectSizeSmall, unsigned int negativeEffectSizeBig);
Pet() {};
std::string GetName() const;
unsigned int GetVim() const;
void InflictPositiveEffect();
void InflictNegativeEffect(EffectSize effectSize);
};

Dog.h

#pragma once
#include "Pet.h"#define _PositiveEffectSize 3
#define _NegativeEffectSizeSmall 0
#define _NegativeEffectSizeBig 10

class Dog : Pet {
public:
Dog(std::string name, unsigned int vim) : Pet(name, vim, _PositiveEffectSize, _NegativeEffectSizeSmall, _NegativeEffectSizeBig) {}
};

Спасибо за помощь и идеи 🙂

0

Это может быть немного старой школы, но это сэкономит огромные деньги, так что имейте это в виду

Вы можете использовать шаблоны, но это может быть очень тяжело для чего-то, что останется статичным. Так что, если вы не планируете что-либо менять во время выполнения (без компиляции), вы можете просто объявить static. Основным преимуществом этого является то, что вы можете заранее знать, сколько данных у вас есть и сколько памяти вы собираетесь использовать. Это также выглядит очень чисто и действует как таблица для ввода данных. Недостатком, очевидно, является то, что вы должны объявлять все переменные во время компиляции. И если у вас в значительной степени разные методы, это может стать очень и очень уродливым в методологии. Вы можете исправить это, создав классы логики, которые обрабатывают операционные различия.

enum { dog = 0, cat, bird, ever_other_member, MAX_PETS }
static struct petinfo
{ const char * name, uint next, next2; char *etc; //all your vars
const char *getpetname : const(); void setpetname(const char *); //all the functions
//now if you dont conclude with a semicolon you can define an array which are the only instances of this object allow.
} pets[MAX_PETS] =
{
{ "dog", 4, 5, "this lines up with the variable order declared above" }
{ "cat", 3, 4, "" }
{ "bird", 10, 20, "" }
{ "other one", 0, 0 , "" }
}; //semicolon here ends the class

Затем в вашем файле cpp (или в любом другом месте) вы можете объявить свои функции выше.

const char *petinfo::getpetname : const() { return name; }
void petinfo::setpetname(const char *n) { name = n; }

Это также позволит вам объявить статические переменные, которые являются постоянными для всех ваших питомцев. Вы бы просто объявили их в вашем списке переменных как:

static const bool wild = false; //I think this is a poor example

Для доступа к этим данным вы просто:

pets[dog].getname();

или перебрать их.

for(int i = 0; i < MAX_PETS; i++) print(pets[i].getname());

Если у вас есть объявленный метод, например, talk, вы можете справиться с этим несколькими различными способами, но для простой реализации вы можете просто использовать систему case.

void speak(uint type)
{
switch(type)
{
case dog: print("bark"); break;
case cat: print("meow"); break;
case bird: print("chirp"); break;
}
}

Это главная слабость этого типа. Если у вас большая разница в функциональности по сравнению с большой разницей между переменными-членами, вам лучше использовать либо наследование, как вы делали выше, либо использование шаблонов. Основная сила этого метода в том, что если у вас много переменных с разной статистикой, но очень схожей функциональностью. Главным образом потому, что это намного меньше, чем при использовании шаблонов, и его очень легко читать и редактировать без огромного количества кода. Кроме того, если у всех ваших собак одинаковые базовые характеристики, это можно использовать в качестве отправной точки.

chasester

-1
По вопросам рекламы [email protected]