# Function return type

This topic is 2166 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi there, I'm developing a component-based engine, thus far, everything has gone well, however I've encountered a problem in my stat component: I'm using 2 types of stats, independant stats (The so called "attributes" (As of strength, agility, etc...)) and dependant stats (Physical attack, magic defense, etc...) and they're both stored in a polymorphic vector which I'm accessing through a function, and that's where the problem has arose. The "DependantStat" class is derived from "IndependantStat", but it has obviously got more functions which cannot be accessed from an "IndependantStat" pointer. What I've used so far is something like the following:

template<typename T = IndependantStat>
T *GetStat(StatType type)
{
...get the desired stat...
if(type >= STAT_HP)
{
return static_cast<DependantStat*>(stats[i]);
}
else
{
return stats[i];
}
}


So, what I would like to do is make a function that can ONLY return either an "IndependantStat" or a "DependantStat".
Obviously, if there's a better way to do this, please tell me.

Edited by Darkilon

##### Share on other sites

No idea what you are trying to achieve there. You don't need to cast a base class pointer to a derived class pointer.

You are probably wanting to use virtual functions?

Maybe if you gave some context about what you are trying to do with your pointers we might be able to give you better advice.

##### Share on other sites

Well, I'm casting it because I want to use the derived class' functions, which is stored in a base class vector.
What I'm trying to achieve is the following:

#include <iostream>
#include <vector>

class Base{
int x;

public:
Base(int x) : x(x){}
int GetX(){return x;}
};

class Derived : public Base{
int y;

public:
Derived(int x, int y) : Base(x), y(y){}
int GetY(){return y;}
};

int main()
{
Base *b = new Base(3);
Derived *d = new Derived(1, 7);

std::vector<Base*> test;
test.push_back(b);
test.push_back(d);

std::cout << test[0]->GetX() << "\n";
Derived *downCast = static_cast<Derived*>(test[1]);
std::cout << downCast->GetX() << ", " << downCast->GetY() << "\n";

std::cin.get();
return 0;
}

All of which should go in a function which takes the "ClassType" as a parameter and if the chosen type is "Base", then simply return an element from the vector "test", else cast said element to "Derived" and return it.
I know this isn't quite elegant, so, as I said earlier, if you know a better way to achieve something like this, please, tell me.

Edited by Darkilon

##### Share on other sites

Normally you would make GetY virtual in the base class and make it return a dummy value or throw an exception. Not a great design though.

It's generally a bad design having to know the exact type of derived class a base class pointer is pointing at. If you make a function virtual then the this pointer will be of the correct type in the derived class implementation.

EDIT: You could also have 2 vectors one of Base and another of Derived. That would make more sense for your example code.

##### Share on other sites

Yeah, I had thought of both solutions, although 1) would be quite redundant imho, I could just stick everything in one class, which isn't encapsulation-friendly, while for 2) I would need 2 different GetSomething() functions, which would work on 2 different vectors. What's your suggestion, then? Which one should be preferred over my design?

EDIT: Also, 2) wouldn't work for me now, I guess, since I would need to know in advance which type of ClassType I need.

Edited by Darkilon

##### Share on other sites

I'd use 2 vectors.

Depends on what you do with the values though. If you just want to output them have a Print virtual function. Your example is too abstract to make meaningful suggestions.

##### Share on other sites

Why is DependantStat class is derived from IndependantStat? Sure, dependant stats depend on independant stats, but dependence isn't a reason for inheritance.

DependantStat is-a IndpendantStat ? That's contradictory.

Why is each stat a separate class? Does someone with Physical Attack ever not have Strength?
Doesn't any entity that might have one attribute, almost certainly have the other attributes as well (even if they are set to 0)?
Even a breakable wall that has Health might need Physical Defense, and its Wisdom could just be set to 0, which would make the Magical Defense 0, so spells can be cast on the wall without failing because of a missing Magic Defense attribute. And the wall's Poison Immunity should be set to 100%.

If an entity has one attribute, it should most likely have all of them.

struct IndependantAttributes
{
int wisdom;
int endurance;
int strength;
int agility;
};

class DependantAttributes
{
int maxHealth;
int maxMana;
int physicalAttack;
int physicalDefense;
int magicAttack;
int magicDefense;
int attackSpeed;

int poisonResistance;
int fireResistance;
int waterResistance;
};

struct EntityAttributes
{
//The "real" stat level, from the character's level ups or whatever.
IndependantAttributes baseStats;
DependantAttributes derivedStats;

//After adjustments as applied by buffs, debuffs, and equipment being worn.
};

Now I might be rather ignorant of component-based design - I have an interest in it, and have read alot about it, but haven't yet actually wrote any entity-component-systems... still, having each seperate attribute it's own component seems like over-engineering to me. I understand the need to make the entire collection of attributes a component (not every entity has attributes), but I don't see the need to separate each attribute into its own component.

Is there any non-contrived valid case where you'll need an entity to have one attribute without another, where merely setting the other attributes to 0 or MAX won't work?

Edited by Servant of the Lord

##### Share on other sites

I know where you're coming from, and that's what I've been doing for quite a while, but I've encapsulated my stats in a class rather than a single variable because I want modifiers to them. Like, my "IndependantStat" (Or rather, I actually called it "BaseStat") has a vector of "Modifiers" (A struct which explains how to modify a specific attribute) and various functions like AddModifier(), RemoveModifier(), GetModifier() and a CalculateFinalValue() (Which takes into account ALL the modifiers applied to such stat), while my "DependantStat" HAS to be in a "is-a" relationship with "IndependantStat" because not can only it be modified by modifiers, but it has also got a vector of "IndependantStatBoost", which is nothing more than a struct with a pointer to a "BaseStat" and a "ratio" (float) variable. It works like this:

BaseStat VIT(30);  //Base value of VIT set to 30
VIT.AddModifier(new Modifier(FLAT_MODIFIER, 100)); //Adds a flat modifier of 100 to VIT, now VIT = 130

DependantStat HP(100);  //Base value of HP set to 100
HP.AddIndependantStatBoost(new IndependantStatBoost(&VIT, 0.5f)); //Now HP = 165


##### Share on other sites

Why don't you just have an empty vector for dependent stats? (I'd be annoyed with you spelling dependent as dependant if I was working on this code, btw).

I think you added inheritance for no real solid reason.

##### Share on other sites
I'm going to have to agree that inheritance is probably the wrong solution.

Here's how I'd do it:

typedef float StatT;    // or whatever

struct UnmodifiedStat {
StatT value;
};

struct Modifier {
virtual StatT Modify(StatT input) = 0;
};

struct CoolModifier : Modifier {    // just interface inheritance, not implementation inheritance!
StatT Modify(StatT input) {
return input + 3.0f;
}
};

struct ModifiedStat {
UnmodifiedStat Base;
std::vector<std::shared_ptr<Modifier> > Modifiers;

StatT ComputeValue() const {
StatT value = Base.value;

for(const std::shared_ptr<Modifier>& mod : Modifiers) {
value = mod->Modify(value);
}

return value;
}
};

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 16
• 9
• 15
• 9
• 11