C/C++ Help
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
 
User Name:
Password:
Remember me
Iron Speed
 
Go Back   Dev Articles Community ForumsProgrammingC/C++ Help

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Display Modes
 
Unread Dev Articles Community Forums Sponsor:
Ajax Application Generator Generate database and reporting .NET Web apps in minutes. Quickly create visually stunning, feature-rich apps that are easy to customize and ready to deploy. Download Now!
  #1  
Old April 30th, 2008, 08:54 PM
JBudOne JBudOne is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Apr 2008
Posts: 3 JBudOne User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 20 m 15 sec
Reputation Power: 0
Classes - Downcasting issues

Hey guys, I'm trying to make an RPG game, and I'm having problems with downcasting. So I've got a class, Item, and a couple inherited classs, Weapon / Armor (two different classes). Now, I've tried the following statements, and have received the following results:

Original Weapon:
Name - A Sword 1d2 } Attributes of the
Appearance - '|' } Item Class
note: the name is a string, that is created by a method in the weapon class (based on the weapon type, die and sides)

Type 0 }
Sides - 2 } Attributes of the
Die - 1 } Weapon Class




Code:
Item* i = &t->item.at(0); // This will return an item, that we know (in these testing cases) is a weapon


::Weapon* w1 = (Weapon*)i;
// Results
// Name: A Sword 1d2
// Appearance: '|'
// Type: - 4429968
// Sides: 0
// Die: -842203136


::Weapon* w2 = i;
// Results
// Error, doesn't work


::Weapon* w3 = dynamic_cast<Weapon*>(i);
// Results
// Name: Expression cannot be evaluated
// Appearance: Expression cannot be evaluated
// Type: Expression cannot be evaluated
// Sides: Expression cannot be evaluated
// Die: Expression cannot be evaluated


::Weapon* w4 = static_cast<Weapon*>(i);
// Results
// Name: A Sword 1d2
// Appearance: '|'
// Type: - 4429968
// Sides: 0
// Die: -842203136


::Weapon* w5 = reinterpret_cast<Weapon*>(i);
// Results
// Name: A Sword 1d2
// Appearance: '|'
// Type: - 4429968
// Sides: 0
// Die: -842203136




The weapon inherits from an item,

Code:
class Weapon : public Item
{
...
};


and the Item is just some normal class,

Code:
class Item
{
...
};



I'm a huge noob to C++, I come from C# instead. Could anybody help me out with this and tell me what's going on, and what I can do to fix this? It'd be greatly appreciated, thanks so much (btw, I've asked this on another forum board, and someone had suggested writing all weapon and item types to a text file, and reading the information there - although I do appreciate his/her help, I would much rather keep the information in here for now). Thanks guys.

Reply With Quote
  #2  
Old May 1st, 2008, 04:50 AM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Click here for more information.
 
Join Date: Sep 2005
Posts: 595 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 1 Week 1 Day 10 h 41 m 27 sec
Reputation Power: 3
Ok first of all, if you need to downcast explicitly you probably already have a flawed/non optimal design. In c++ you should try to avoid explicit casting.

Second, if you must do a polymorphic downcast then prefer to use dynamic_cast. Unless you are absolutely sure and want to avoid the overhead of dynamic_cast, then you can use static_cast. But you should only do that in performance critical code.

Now in your case we need to see more code to see what is going wrong. I am _guessing_ that your Item container is storing the objects by value instead of storing pointers. So you are experiencing the fabled c++ slicing where you 'cut off' the parts of the derived class and only keep the base class parts.

Can you show us the full code for the Weapon/Item class plus the calling code and the container?
__________________
Current project: roborally

Reply With Quote
  #3  
Old May 1st, 2008, 11:55 AM
JBudOne JBudOne is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Apr 2008
Posts: 3 JBudOne User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 20 m 15 sec
Reputation Power: 0
Sure things..

Code:
// Item.h
#ifndef ITEM_H
#define ITEM_H

#include <string>
#include <sstream>
#include <stdlib.h>

using namespace std;

class Item
{
public:
	// Constructor / Destructor
	//Item();
	Item(string name = "Nothing", int weight = 0, int value = 0, bool stackable = false, char appearance = ' ');
	virtual ~Item(); // Destructor is different for armor/weapon/etc.

	bool Inventory; // On the map or in an inventory
	bool wielded; // Is this is wielded?

	string name; // Name of the item
	int weight; // Weight of the item
	int value; // What is the value of the item (useful for considering if a monster should pick up the item or not)
	bool stackable; // Is the item stackable?
	char appearance; // Appearance of the item
	int itemType; // -1 None, 0 Weapon, 1 Armor

private:
};

#endif


Code:
// Weapon.h
#ifndef WEAPON_H
#define WEAPON_H

#include <string>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <sstream>
#include "Item.h"

using namespace std;


class Weapon : public Item
{
public:

	enum  weaponType
	{
		None,
		Sword,
		Axe,
		Mace,
		Bow,
		Sling
	};

	Weapon();
	Weapon(Item i);
	Weapon(Item i, Weapon::weaponType type, int dice, int sides, int dmg = 0, int hit = 0, int multiplier = 1, float crit = 0, string specialName = "");
	~Weapon();

	int GetHit(); // Get the weapon's hit (this is not usually the total that the character hits for)

	weaponType type; // Weapon type
	int dice; // Number of die
	int sides; // Number of sides of the dice
	int dmg; // to-dmg bonus (added onto character's total to-dmg)
	int hit; // to-hit bonus (added onto character's total to-hit)
	int multiplier; // How many times to hit
	float crit; // Chance to critical strike
	string specialName; // This is for names such as "Golem's dagger" where Golem's would be the name
	
private:
	void SetName(); // Set the name of the weapon
	string WeaponTypeString();
};

#endif




Code:
	::Weapon tmpW(Item(), Weapon::weaponType::Sword, 1, 2);
	::Armor tmpA(Item(), Armor::armorType::Chest, Armor::armorMaterial::Leather, 1);
	tmpE.character.e.melee = tmpW;
	tmpE.character.e.chest = tmpA;

Here we create a weapon and armor, and then equip it to the enemy character
(Each character will have a melee slot (weapon), a chest slot (armor), and a few inventory slots (item)).


Code:
			// Drop the weapon
			if (e.at(inTheWay).character.e.melee.name != "None")
			{
				Weapon w = e.at(inTheWay).character.e.melee;
				w.Inventory = false;
				w.wielded = false;
				this->items.push_back(w);
				t->GetItem(w, (int)this->items.size() - 1);
			}

			// Drop the armor
			if (e.at(inTheWay).character.e.chest.name != "None")
			{
				Armor* a = &e.at(inTheWay).character.e.chest;
				a->Inventory = false;
				a->wielded = false;
				this->items.push_back(*a);
				t->GetItem(*a, (int)this->items.size() - 1);
			}

We start by checking if the enemy is holding a weapon or armor piece, and if so we create a variable (one is just a normal variable, and the other is a pointer - this is just for testing cases to see if one works and the other doesn't). Next we put this item onto the tile that the enemy was standing on (pushing it into the vector of items).


Code:
character->character->PickupItem(t->RemoveItem(t->items.size() - 1));

Item Map::Tile::RemoveItem(int index)
{
	this->itemIndex.erase(this->itemIndex.begin() + index);
	Item i = this->items.at(index);
	this->items.erase(this->items.begin() + index);
	return i;
}

void Character::PickupItem(Item item)
{
	if (!this->i.inventoryFull)
		i.AddItem(item);
}

After the character walks onto the tile and says yes to picking up the item, we come to this statement..


Code:
				if (c.i.slots.at(slot - 'a').itemType == 0)
				{
					::Weapon w = (Weapon)c.i.slots.at(slot - 'a');

					if (c.e.melee.name == "Nothing")
					{
						Item item = c.e.melee;
						c.dmg -= c.e.melee.dmg;
						c.hit -= c.e.melee.hit;
						c.e.melee = w;
						c.dmg += c.e.melee.dmg;
						c.dmg += c.e.melee.hit;
						c.i.slots.at(slot - 'a').~Item();
						c.i.slots.at(slot - 'a') = item;
					}
					else
					{
						c.e.melee = w;
						c.dmg += c.e.melee.dmg;
						c.dmg += c.e.melee.hit;
						c.i.slots.at(slot - 'a').~Item();
					}
				}

And this is the main code, where we wield the weapon. You can only see what statement that I used to convert the item to a weapon (this is because I've done that testing much earlier, but I thought it'd be more useful to show you how my program is set up).



I know this all may look very messy and noobish :$ bare in mind I'm very new to C++. Anyways, thanks so much for the help =) I really appreciate it.

Reply With Quote
  #4  
Old May 2nd, 2008, 02:51 AM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Click here for more information.
 
Join Date: Sep 2005
Posts: 595 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 1 Week 1 Day 10 h 41 m 27 sec
Reputation Power: 3
Ok one big difference between C++ and c# (or java) is that c++ uses value semantics instead of reference semantics. You should have a look at this link for more information:
http://www.parashift.com/c++-faq-li...-semantics.html

You still have not shown how you create your container of items but I am pretty sure you are experiencing slicing. See a little explanation of it here

It comes down to the fact that you probably need to store a pointer to Items in your Item container instead of storing them by value. Even in that part where you are dropping the armor and using a pointer just for testing, you are push_back *a, which means you are not storing a pointer to the object but a sliced copy of it.

I hope this gets you on your way a bit, if not, show me your Item container and I may be able to give you some more specific advice. You are experiencing slicing in many other places too by the way, and you should almost never called a destructor directly ( c.i.slots.at(slot - 'a').~Item(); ) but only through delete.

Reply With Quote
  #5  
Old May 3rd, 2008, 09:57 PM
JBudOne JBudOne is offline
Registered User
Dev Articles Newbie (0 - 499 posts)
 
Join Date: Apr 2008
Posts: 3 JBudOne User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 20 m 15 sec
Reputation Power: 0
Hey again, so here's my containers:

Code:
// This is for the characters inventory
std::vector<Item> slots;

struct Equipment
{
	Weapon melee;
	Armor chest;
};

// This is the container for the tile's items
std::vector<Item> items; // All of the items on this tile


I tried simply changing everything from a value to a pointer, but I don't think that will work: what if I create a weapon and armor piece in the constructor for the map class (for one of the monsters in the map) and equip it to the monster. Wouldn't the weapon be gone at the end of the method? and if not, wouldn't it be gone after the monster dies, the item is put into the tile and the monster is deleted? My only other guess is to create a vector of items within the whole gameloop and have all the items, whether they are in the character class or the tile class or the map class, point to the items in the gameloop. Is this what I should be doing? I can't think of any examples but I don't see this working very well later on in the game. Anyways, thanks so much for your help - putting up with my noobishness. Really appreciate it =)

Reply With Quote
  #6  
Old May 4th, 2008, 06:03 AM
Icon's Avatar
Icon Icon is offline
Command Line Warrior
Click here for more information.
 
Join Date: Sep 2005
Posts: 595 Icon User rank is Private First Class (20 - 50 Reputation Level)Icon User rank is Private First Class (20 - 50 Reputation Level) 
Time spent in forums: 1 Week 1 Day 10 h 41 m 27 sec
Reputation Power: 3
I see your point. A global vector of items is a solution but maybe not the most elegant. But still, even with a global vector of items you would still experience slicing. Seriously. You need to change the type of your vector to hold pointers to items, without that there is no polymorphic behaviour. You can create new objects using the new operator. The downside of that is that you will need to clean up the memory yourself but you could use a boost::shared_ptr for that. Boost::shared_ptr's work well with vectors. Alternatively you could use boost:tr_vector. See http://boost.org.

But still, you should try to grasp the problem of slicing first. vector<Item> is not going to work for derived classes of Item.

Reply With Quote
Reply

Viewing: Dev Articles Community ForumsProgrammingC/C++ Help > Classes - Downcasting issues


Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

 Free IT White Papers!
 
Accelerating Trading Partner Performance
One in five. That's how many partner transactions have at least one error. That is an amazing statistic, particularly given the extraordinary leaps in innovation across the global supply chain during the past two decades. Download this white paper to learn more.

 
Competing on Analytics
This Tech Analysis is designed to help identify characteristics shared by analytics competitors, and includes information about 32 organizations that have made a commitment to quantitative, fact-based analysis.

 
Cost Effective Scaling with Virtualization and Coyote Point Systems
An overview of the industry trend toward virtualization, how server consolidation has increased the importance of application uptime and the steps being taken to integrate load balancing technology with virtualized servers.

 
Five Checkpoints to Implementing IP Telephony
Implementation planning for IP PBX software and IP telephony has become vital as businesses replace discontinued legacy PBX phone systems. This informative whitepaper outlines five &quot;checkpoints&quot; for any implementation plan that will help make IP communications a successful proposition.

 
Hosted Email Security: Staying Ahead of New Threats
In the last two years, email has become a fierce battleground between the nefarious forces of spam and malware, and the heroes of messaging protection. The spam volumes increased alarmingly every month, bringing clever new forms of phishing and virus propagation attacks.

 

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 

Iron Speed




© 2003-2008 by Developer Shed. All rights reserved. DS Cluster 3 hosted by Hostway