functions and structs

So I am making a game and decided to put fighting in it. To do this I made a struct (since it will all be public anyways), with lets say an object named rat. I make all of the stats in a function called create_creature. Can I use these stats of object rat in a different function?
Yes if your function returns the instance of the "rat" class that it created.

EDIT: Although the creation of objects is mostly done with it's constructor...
Last edited on
By the sounds of it, "create_creature" should be a constructor of your Creature struct. If you do want to separate both, the best (?) way is to pass a Creature object to create_creature by reference.

If by "create_creature", you mean a function that calculates some stuff and then constructs a Creature object based on the results, you're going to have scope issues (i.e. your object is destroyed when the create_creature function ends). To ensure persistence, you need a "place" to hold your creature object that exists inside the using scope. Then, pass that "place" to your create_creature function.

For example, imagine a function fight_random_encounter, that generates a creature and runs the combat algorithm versus your player:
1
2
3
4
5
6
7
8
9
10
fight_random_encounter() {
// TRY 1
create_creature();
fight(creature); // What is creature? Where is it? It might have been created in create_creature, but it died when that function ended!
// TRY 2
Creature Rat = create_creature(); // create_creature returns the creature it created, which is assigned to Rat.... but why not do it directly in the constructor?
// TRY 3
Creature Rat;
create_creature(Rat); // create_creature accepts a Creature reference and assigns it values!
}

To summarize: fight() needs access to the Creature object, which means it has to exist inside the calling scope (here: fight_random_encounter). This means that any function create_creature needs a way to return this object to the caller.

You could wonder if TRY3 is actually better than doing it through the constructor. In the current use, it's not. However, you might want to fight multiple creatures!
1
2
3
4
fight_random_encounters() {
     Creature rats[5];
     for (int ir = 0; ir < 5; ++ir) create_creature(rats[i]);
}

Yes, that can also be done by constructors, but this feels and looks more clear to me.

[edit]
Please never use the name "create_creature". I don't know why, but I mistyped it nearly every time.
Last edited on
yeah i was just using an example. so would this work (plz excuse the sloppiness)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

struct monster
{
int health;
string name;
}rat;

//main would just send me to different functions

void fight()
{
monster_create(rat);
//fighting ensues and rat has all of its stats
}

void monster_create()
{
rat.health = 5;
rat.name = "rat";
return (rat);
}


if this is wrong plz explain why and thank you in advance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct monster{ //This is mostly correct. You don't strictly need the rat.
    int health;
    string name;
};

void fight(){
    monster rat = monster_create(); //Create a variable of type monster, name it rat,
                // then assign it the value monster_create() returns.
}

monster monster_create(){ //This function is of type monster, because it needs to return type monster.
    monster rat; //Create a variable of type monster, name it rat.
    rat.health = 5; //Make the rat's health 5.
    rat.name = "rat"; //Make the rat's name rat.
    return rat; //Return rat to void fight().
}


You should avoid creating a new monster every time you call fight. Instead, you should create a monster when it's needed, and then pass that monster to fight.

If you did want to do it a little closer to your way, you could just do this:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct monster{ //This one preallocates a global instance of monster called rat
    int health;
    string name;
} rat;

void fight(){ //Don't need to create a monster variable, it already exists.
    monster_create();
}

void monster_create(){ //This function doesn't return anything, so it's of type void.
    rat.health = 5;
    rat.name = "rat";
} //No return because rat is accessible from fight as well as monster_create. 
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using namespace std;

          
struct Monster {
	Monster(string n, int h = 5) {
		name = n;
		hp = h;
	}
	string name;
	int hp;
};

void Fight(Monster* m1, Monster* m2) {
       //.....
       delete m1;
       delete m2;
}

int main () {

	string names[3] = {"RatKing, Jimbo, Bob"};
	int hp[3] = {5, 15, 25};

	for (int i = 0; i < 3; i++) 
		Fight(new Monster(names[i], hp[i]), new Monster(names[i], hp[i]));

	return 0;
}

Last edited on
@IceThatJaw: that seems like very, VERY bad practice. What happens if I decide to do this:
1
2
3
4
monster *rat = new Monster("Bob", 20), *mouse = new monster("Mouse", 10);
Fight(rat, mouse);
delete rat;
delete mouse;

Hiding delete statements in a function that didn't allocate the memory is bad [except constructor/destructor combos]. Fight has no business deleting m1 and m2. main() is the owner of those variables.

If you're going to pass temporary dynamic objects anyway, you might as well create them in Fight.

[edit]
Why on earth did I name my rat "Bob"?
Last edited on
Then just remove the deletes. I would never let my client declare variables the way you did so I would have my ass covered either way. They would only be able to pass in the name and/or health and I would have a handle class that take of everything. I hate procedural programming to be honest. Encapsulation and information hiding is what got me into programming in the first place.
Last edited on
Encapsulation and information hiding is what got me into programming in the first place.

Okay, but your code does pretty much the opposite. There is no logical reason for "Fight" to delete your objects, except your personal reasoning "I plan to call new in the parameters". There's a difference between information hiding and code hiding.

(P.S.: You made a typo in your code snippet:
string names[3] = {"RatKing, Jimbo, Bob"};
must be
string names[3] = {"RatKing", "Jimbo", "Bob"};
Thought I'd mention in case Aramil decides to copy paste.)
@gaminic: Don't worry, I wouldn't copy and paste because this is just an example and then I wouldn't learn anyting. So I knew the object rat of the struct is global scope, but your saying with your second example that all of its attributes (rat.health, rat.name) are global too?
Aramil, anything that's declared globally can be used globally. Think of the data structure 'monster' as the same thing as the data structure 'int'. While the value of an 'int' is an integer, the value of a 'monster' is a variable of type int and a variable of type struct string.

The biggest problem that new programmers have with data structures (or classes for that matter) is that they think of the structure / class as being different than a variable, where they are not, in fact. They have exactly the same properties as any other variable, except that other variables are not able to contain members, only values. In every other way, they are indistinguishable.
Last edited on
no i knew that they were very similar (besides objects and public and private and what not), i just didn't know what their default scope is. Can two different structures have the same object
I'm not sure what you're talking about now...

An object is an instantiation of a class, e.g. MyClass MyObject = new MyClass;
--> MyObject is an instantiation of MyClass.
You could draw the parallel with "regular variables": int myInt = 6;
--> myInt is an instantiation of the int "class".

The scope of an object depends on where it is declared, i.e. where the object is created.
1
2
3
4
5
6
7
8
9
10
11
myClass myGlobalObject; // Can be used by any function, anywhere.
void myFunction () {
     myClass myFuncObject; // Only exists during the call of this function. No other function can use it.
}
void myFunction2(myClass &anObject) { ... }
int main() {
    myClass myMainObject; // Exists during the entire runtime of the program, but...
                                        // can't be accessed by other functions unless it is passed to it.
    myFunction2(myMainObject); // Main can pass objects from its scope to functions.
    return 0;
}

For any object in its scope, a function can access all public members.
1
2
3
4
5
6
int main() {
    cout << "Value of global object: " <<  myGlobalObject.value << endl;
    cout << "Value of main object: " << myMainObject.value << endl;
    cout << "Value of func object: " << myFuncObject.value << endl; // ERROR - main doesn't know    myFuncObject!
    return 0;
}

Last edited on
what I am talking about is you have struct a, fuction b, function c (both void), and the struct has members (int) 1, 2, 3, 4, 5 and object d declared at the end of the struct. If I make d.1 = 5 and d.2 = 7, in void b, and then just make c print the values without doing anything else will that work?
You still have to inialize object d.
nvr mind i figured it out myself
im sorry that sounds rude. i mean i just tested it
Topic archived. No new replies allowed.