Creating and instance of a class in a class

Started by
9 comments, last by SoundFX 17 years, 9 months ago
Hello, somewhat new here, but Ill skip the introductions and get on with my problem. I am creating a text-based rpg (yea I know, not another one), but I am having a few problems. I have a job class, which holds all my spells and hit die and attack bonuses and such. I can create one of those on its own fine using my own constructor. job_info.h

#ifndef job_info_H
#define job_info_H
#include <string>
#include <vector>

class job_ability {
public:
	std::string name; //the name of our spell
	//when using an ability deal direct damage(melee or a spell) then do the damage boost
	//directDamage + damageBoost = totalDamage; ???
	int directDamage;	//the dice it will roll for damage (xd4-xd20)
	int damageBoost; //my damage boost
	double multiplier; //incase we need to do 2 or more dice	
	int manaCost; //mana consumed upon using
	int levelReq; //level required before gaining it
	std::string preReq; //pre-requisites?
	//skills with buffs/debuffs/and round-lasting effects (like bleeding/poison)
	int myAttackMod; //if the ability boosts my attack mod
	int myDefenseMod; //if the ability boosts my defense mod
	int enemyAttackMod; //if the ability lowers enemy attack mod
	int enemyDefenseMod; //if the ability lowers enemy defense mod
	int rounds; //the number of rounds an ability will last (0 is forever, like an Aura)	
	int actions; //number of actions this will take
	
	int mpDrain; //for use with mpDrain skills
	int hpDrain; //for use with hpDrain skills
	//Auras
	int on; //1 yes || 0 no

	//Stealth/Jump  Stealth can be seen through (Theif/Ninja), Jump you cannot be hit (Dragoon)
	int stealthMod; // 100 is cannot be hit

};

class job_info {
public:
    job_info(int choice); //this will allow us to choose our class via a prompt.
    std::string name;
	int hitDie;
	int manaDie;
	int attackBonus;
	int spellDefense;
	
	//store all of our abilities in this vector for use
	//they will be filled by the becomeClass functions
	std::vector<job_ability> myAbilities;
	
	//functions
    //void Berserker();
    //void BlackKnight();
	void BlackMage();
    //void BlueMage();
    //void Dragoon();
    //void Engineer();
    //void Fighter();
    //void Marksman();
    //void Monk();
    //void Ninja();
    //void Summoner();
    //void Thief();
    //void WhiteKnight();
    //void WhiteMage();

};
#endif



job_info.cpp

#include "job_info.h"
#include <string>
#include <vector>
#include <iostream>

using std::string;
using std::vector;


job_info::job_info(int choice)
{
	switch (choice) {
        case 0: job_info::BlackMage(); break;
        //more classes later
    };
}


void job_info::BlackMage()
{
	name = "Black Mage";
	hitDie = 4;
	manaDie = 12;
	attackBonus = 0;
	spellDefense = 0;
	
	//Fire spell
	job_ability Fire;
		Fire.name = "Fire";
		Fire.directDamage = 8; 
		Fire.multiplier = 1;
		Fire.manaCost = 4;
		Fire.levelReq = 1;
        Fire.actions = 1;
			
	
	//Start filling our container
	myAbilities.push_back(Fire);
    
/*note to Gamedev, i took out the other 20+ skills to save space :O */

}


As you can see I can ask for a choice of input, but only 1 option is available at the moment. The important part is that it works. If I try to create a character though, similary named 'character_info' with a member of type job_info, called 'myJob'. I cannot figure out how to be able to instantiate (that the right word?) a job_info inside my character_info's constructor. Sorry for the mess of comments inside the following code, im trying to figure out how to get it to work, its an uphill battle, my latest attempt was to return a value with a function and use it to create 'myJob'. character_info.cpp

#include <string>
#include <iostream>
#include <vector>
#include "job_info.h"
#include "character_info.h"
//#include "weapon_info.h"
//#include "race_info.h"

using std::cout;
using std::cin;
using std::string;
using std::endl;
using std::vector;


int character_info::selectJob() {
	cout << "\nPlease choose a class by selecting its corresponding number:\n0. Black Mage" << endl;
    int choice;
	
    cin >> choice;
    //job_info myJob(choice);

    //cout << "\nCongratulations, you are a: " << myJob.name << endl;

    //cout << "You have these abilities: \n";

    //for (vector<job_ability>::const_iterator it = myJob.myAbilities.begin();
    //        it != myJob.myAbilities.end(); ++it)
    //{
    //    cout << (*it).name << endl;
    //};
	
	return choice;
}


void character_info::setAttributes() {
    //we need to set all our attributes here as well as change the modfier accordingly
    while (attributePoints > 0) {
        cout << "\nPlease spend your attribute points.  You have " << attributePoints << " to spend." << endl;
        
        cout << "\nPlease choose an attribute to add points to: "
            << "\n1: Strength" << "\n2: Dexterity" << "\n3: Vitality" << "\n: Energy" << "\n: Spirit";

    int choice;
        switch (choice) {
            case 1: ++strength, --attributePoints; break;
            case 2: ++dexterity, --attributePoints; break;
            case 3: ++vitality, --attributePoints; break;
            case 4: ++energy, --attributePoints; break;
            case 5: ++spirit, --attributePoints; break;
            default: cout << "\nThat is not a valid option please choose again." << endl; break;
        };
    };    
    cout << " You have " << attributePoints << " to spend" << endl;
}

void character_info::selectRace() {
    //choose our race and change the attribute the racial bonus gives
}

void character_info::selectAbilities() {
    //show the a list of available abilties by level = 1 and pre-requisite == none
}

character_info::character_info() {
    //ask for name
    cout << "Please enter your characters name: " << endl;
    cin >> name;

    //set all defaults
    strength = 10;
    dexterity = 10;
    vitality = 10;
    energy = 10;
    spirit = 10;
    luck = 10;
    currentExp = 0;
    nextExp = 1000;
    level = 1;
    actions = 1;
    attributePoints = 15;
    abilityPoints = 3;
    isPoisoned = false;
    isBleeding = false;

    //ask to choose a job
    myJob(selectJob());
    //ask to plug in attribute points
    setAttributes();
    //ask for a race
    //setRace();
    //ask for abilities
    //selectAbilities();

}




character_info.h

#ifndef character_info_H
#define character_info_H
#include <string>
#include "job_info.h"
//#include "weapon_info.h"
//#include "race_info.h"

class character_info {
public:
    //Our default constructor will handle the name entry as well as set all the defaults for our character
    character_info();

	std::string name;
	job_info myJob;
	//weapon_info myWeapon;
	//race_info myRace;

	int level;
	double currentExp, nextExp; 
	int	currentHealth, maxHealth, currentMana, maxMana; 
	int strength, dexterity, vitality, energy, spirit, luck, strMod, dexMod, vitMod, engMod, sprMod; 
	int actions, attributePoints, abilityPoints; 
    bool isPoisoned, isBleeding;  //Will allow us to perform DoT() checks
    

    //We need to select a job
    int selectJob();
    //We need to spend our attribute points first
    void setAttributes();
    //We then need a race
    void selectRace();
    //Lastly, choose our abilities
    void selectAbilities();
    
	
};
#endif


main

#include <iostream>
#include <vector>
#include "job_info.h"
#include "character_info.h"

using namespace std;

int main()
{   
    character_info myInfo; //give us a character
	
    system("PAUSE");
    return 0;
}


Anyway, if someone could hint at what im doing wrong, that would be swell. For reference I am using MinGW Studio and DEV C++, fully updated. (I like them both :D) *Edit: The reason I know its with the job_info stuff is from the compiler. I can also make a jobless character with ease by commenting out the job stuff, but no one likes a plain character*
Advertisement
class character_info {
public:
job_info myJob;
};

You can't instantiate myJob because it's done automatically by the constructor. You can make it a pointer:

class character_info {
public:
job_info* myJob;
};

and then in the constructor you can either set it to null or instantiate:

character_info::character_info()
{
myJob = NULL; //set the pointer to null and instantiate later
myJob = new job_info(); //or instantiate right away
}

EDIT: Oh, I get it, it didn't work because job_info doesn't have a default constructor. Either add a default constructor or have it as a pointer.
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
The pointer seems like a good idea.

I dont want the default constuctor to be used, and from what I read, as long as I specify to use my constuctor I should be ok. That makes sense that when it wants to make 'myJob' is has no default to work with. Time to go read up on pointers, feel free to drop me any links.

*Thanks man: this did the trick right here paired with the job_info* myJob in the header! *
	//ask to choose a job	cout << "\nPlease choose a class by selecting its corresponding number:\n0. Black Mage" << endl;    int choice;	    cin >> choice;    myJob = new job_info(choice);
A minor suggestion: add an explicit keyword to the job_info constructor. The problem is that without explicit, an implicit conversion from int would be possible. It's a hard to find bug.

class job_info {
public:
explicit job_info(int choice);
};

Consider this example (without using the explicit keyword):

job_info info = NULL; //oops, I forgot to make it a pointer

What do you know, there is no compiler error because the compiler writes it like this:

job info(NULL); //calls the constructor

However, if you add the explicit keyword, no implicit conversion would take place and the above line would generate an error.
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Well, there are a few things. In character_info.h you have job_info myJob;, which is good. But then in character_info.cpp in the selectJob() function you have job_info myJob(choice); which is the wrong way to initialize something. If you want to initialize something you do:
class MyClass{    public:        MyClass(int x);                int data;};MyClass::MyClass(int x) :    data(x){    //rest of constructor code here}

You have to initialize stuff in the constructor. So in characher_info.cpp change the line job_info myJob(choice); to myJob = new job_info(choice); (of course, this is after making myJob a pointer, and be sure to delete if after using it).

Second, I don't get why you have the job_info constructor taking a choice, and then later having a switch that just calls public functions. It seems like it would make more sense to do the this:
//in job_info.hclass job_info{    public:        job_info() // remove the switch in job_info.cpp        void BlackMage();        //...all the other functions...};//in character_info.cppint character_info::selectJob(){    cout << "\nPlease choose a class by selecting its corresponding number:\n0. Black Mage" << endl;    int choice;     cin >> choice;    switch (choice)    {        case 0:            myJob.blackMage(); //this way you don't have to make myJob a pointer    }    //...all the other stuff...    return choice;}

But if you really wanted to have the constructor of job_info take the choice and do the switch, then you might want to think about makning the job functions protected/private.

Also, I noticed your tabs are sometimes inconsistent (which leads to messy code). In Dev C++ go to Tools -> Editor Options and then uncheck Smart Tabs box (thats if it is checked, if its not...please for the love of all things holy use tabs better. I know it may just be a mistake, but some lines you have tabbed well, and some seem...out of place?)


EDIT: freak thats a new record for me. three people posted while I was still writing mine...i think i'm slow at writing this stuff...
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Quote:Original post by SoundFX
The pointer seems like a good idea.

I dont want the default constuctor to be used, and from what I read, as long as I specify to use my constuctor I should be ok. That makes sense that when it wants to make 'myJob' is has no default to work with. Time to go read up on pointers, feel free to drop me any links.


Read up on initializer lists first, google for more links if this doesn't help or post more questions of course. Good luck with your game and have fun!

EDIT @MikeTacular: you are still before me and look at how small my post is! Crap.
Heh, its already unchecked. I do however spend lots of time re-tabbing everything! Its just when im trying to solve problems I tend not to care how it looks, and from commenting out, uncommenting, adding new things, moving things, its gets messy, and I want it to work before it looks good. :]

To point out, I used the same name myJob in the selectJob function and in the character_info. Probably a bad idea, but I *knew*(aka was hoping) that they are two different objects.

Ill play with your suggestion on making character_info handle all the switching, Im still learning so Im not sure what works best, faster, or easier. I was trying to start basic (the job) and work my way up (the fight sequence). Yay, on to weapon coding.

Anyway, how do you delete a pointer?
Quote:Original post by SoundFX
Anyway, how do you delete a pointer?


If you instantiate in the constructor, the best way to delete the pointer is in the destructor:

class character_info{public:    ~character_info(); //destructor};character_info::~character_info(){    delete myJob; //delete the pointer                 //if it's an array, you have to call delete [] myJob;}


EDIT: If you instantiate somewhere else, then you'll have to find a place before the pointer gets out of scope and call delete info there. Since it could be a major pain, I advise to always allocate memory in the constructor and deallocate memory in the destructor. Alternatively, you could try std::auto_ptr which will automatically delete the pointer when it goes out of scope, but that's a little bit advanced.
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)
Quote:Original post by SoundFX
To point out, I used the same name myJob in the selectJob function and in the character_info. Probably a bad idea, but I *knew*(aka was hoping) that they are two different objects.

They are, can you explain what you wanted to do?

It is not neccesary to use a pointer if there is no default constructor, use an initializer list, MikeTacular has posted this method. (EDIT: it can be used without need for pointer...myJob(choice))

Quote:Anyway, how do you delete a pointer?

It is simply delete ptr; However, I would recommend to see first how far you get without using pointers. It is not that pointers are that difficult, the syntax and the idea may be a bit weird at first but it's not too bad. It's more that pointers will introduce a whole new set of problems. If you do decide to go about learning pointers, maybe then try inheritance and polymorphism as well, this will help with the design.

[Edited by - DeadXorAlive on July 6, 2006 9:16:45 PM]
If you can avoid using pointers and dynamic memory allocation, do so. You will save yourself lots of trouble. In this case it's probably better to keep myJob as an instance variable, not as a pointer and initialize it to some kind of null job, like choice = -1 and a corresponding function void job_info::NoJob();

That way you don't have to worry about null pointers, allocation and deallocation. Also, don't worry about performance, the compiler should optimize the do nothing function so there will be no overhead calling it.
deathkrushPS3/Xbox360 Graphics Programmer, Mass Media.Completed Projects: Stuntman Ignition (PS3), Saints Row 2 (PS3), Darksiders(PS3, 360)

This topic is closed to new replies.

Advertisement