Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Class inheritance and stuff 2

Status
Not open for further replies.

fugigoose

Programmer
Jun 20, 2001
241
US
Ok, my engine developement has finally reached the stage of mass game object programming. All the objects in the game are deveried from the class 'cls_object', which looks like this:

Code:
class cls_object{

public:
id id;
std::string alias;
cls_renderer* pRenderer;

public:
cls_object();
~cls_object();
void update();
void render();
void onLoad();
int setProperty(const char* name, const char* value);

};

//-----------------------------------
cls_object::cls_object(){
} 

//-----------------------------------
cls_object::~cls_object(){
} 

//-----------------------------------
void cls_object::update(){
} 

//-----------------------------------
void cls_object::render(){
} 

//-----------------------------------
void cls_object::onLoad(){
} 

//-----------------------------------
int cls_object::setProperty(const char* name, const char* value){
return 1;
}

This way i can add any offspring of cls_object to my object vector, which is of type 'cls_object*'. Next I made my first offspring of 'cls_object' called 'cls_guiElement' that
looks like this:

Code:
class cls_guiElement : public cls_object{

public:
int top;
int left;
int width;
int height;
std::string image;
int opacity;
bool bgTransparent;
bool visible;

private:
cls_image* pImage;
RECT rect;
POINT point;

public:
cls_guiElement();
void render();
void onLoad();
int setProperty(const char* name, const char* value);

};

//-----------------------------------
cls_guiElement::cls_guiElement(){
top = 0;
left = 0;
width = 0;
height = 0;
image = "";
opacity = 100;
bgTransparent = 0;
pImage = 0;
visible = 1;
}

//-----------------------------------
void cls_guiElement::onLoad(){
if (image != "") pImage = pRenderer->imageCache[pRenderer->queryImage(image.c_str())];
rect.top = top;
rect.left = left;
if (pImage){
width = pImage->width;
height = pImage->height;
}
rect.bottom = top + height;
rect.right = left + width;
point.x = left;
point.y = top;
}

//-----------------------------------
void cls_guiElement::render(){
if (visible){
if (pImage){
if (bgTransparent){

}else{
pRenderer->blt(pImage->surface, &rect, 1, &point);
}
}
}
}

//-----------------------------------
int cls_guiElement::setProperty(const char* name, const char* value){

if (!strcmp(name, "image")){
image = value;
onLoad();
return 0;
}

return 1;
}

So I was all excited and I hit compile, but it didn't work like it shoud, the image wasnt being rendered and setPropert() was failing. So i did some debuging and found that when i call any of 'cls_guiElement' functions, it still refers back to the empty ones declared in 'cls_object'. Shouldn't the offsprings functions replace the ancestors? One more thing that may help, heres how i'm adding objects and calling their methods in my object vector:

Code:
std::vector <cls_object*> objects;
objects.push_back(new cls_guiElement);
objects[i]->render();
 
When using polymorphism don't forget to make the methods virtual. While I haven't looked very hard at your code, it does seem to be missing that which would cause the problems you describe. You might even make the cls_object an interface by making the methods pure virtual if you will need to implement them differently for each class that inherits them.
 
How do I do that? How does a virtual function differ from a regular function? Can I still have a working function in cls_object that just changes in an offspring?
 
You should declare the destructor as virtual too.



/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Ok I just may, but could someone tell me what the deal is with this whole virtual thing?
 
Code:
class Base
{
public:
	virtual void foo()
	{
		cout << "Base::foo";
	}
};

class Derived : public Base
{
public:
	virtual void foo()
	{
		cout << "Derived::foo";
	}
};

void someFunction(Base& b)
{
	b.foo(); 
}

...
{
	Derived d;
	someFunction(d);
}
The point is : Even though all that someFunction "see" is a Base& it (unknowingly) calls the Derived's foo.

If you only is supposed to call Derived methods, never Base methods, you can declare the method as "pure virtual":
Code:
class Base
{
public:
	virtual void foo() = 0;
};

Which is the C++ way of saying "Base is just an interface. Implementaion is done in derived class(es)."

You may have heard the term "abstract class": An abstract class is a class with at least one pure virtual method.

Code:
class SomeInterface
{
	public:
		// The = 0 declares it as pure virtual
		virtual void method1() = 0;		
}
Perhaps this is something for your generic object class?

----------

Virtual destructors is just to make sure the members are destructed properly. You don't have to think much about it, just make it virtual in the Base definition.
Code:
class Base
{
public:
  virtual ~Base() {}
};





/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
I noticed this snippet
Code:
std::vector <cls_object*> objects;

This is all good and fine, but I want to alert you that it is very easy to crash the system if you treat arrays polymorfically.
Code:
std::vector <cls_object> objects; // Very Bad!

Just so you dont get any funny ideas :)

/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
>crash the system

Well, crash you application that is.

/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Ok...but do virtual frunctions work? That is, can i have an impletation for a base class and a different one that replaces it in a devried class? Like I plan on having multiple inheritance, that is:

Object->Sprite->Car
Object->Sprite->Truck

Where sprite has its own render() function and can function as it is, but car and truck have their own unique render functions to replace the sprites basic render function. Is this possible?
 
>> can i have an impletation for a base class and a different one that replaces it in a devried class

Yes, in fact, you are required to make them virtual for this to work properly. Here's an example of what wouldn't work.

Code:
class CBase
{
  int foo();
};

int CBase::foo() {return 1;}

class CDerived : public CBase
{
  int foo();
};

int CDerived::foo() {return 2;}

int main()
{
  CDerived derived;
  CBase* pBase = &derived;
  cout << derived << endl; // displays 2
  cout << pBase->foo() << endl; // since foo is not virtual, it calls CBase::foo() and returns 1
  return 0;
}

Declare foo as virtual in both classes and the problem is solved: cout << pBase->foo() would return 2.
 
You could also consider the semantics of inheritance.

When you say "Car inherits Sprite" you are also saying "Car is a kind of Sprite" and perhaps thats cool for your case (though I seldom thing of sprites when I think about cars).

Just an idea: You could implement all render functionality in one class. Grouping methods that have something in common (for example they all render) can sometimes be a good thing.

Code:
class Renderer
{
public:
   void render(const Sprite& s) { // Render the Sprite ... }
   void render(Car& s) { // Render the Sprite ... }
   void render(Truck& s) { // Render the Truck... }
   void render(Camel& s) { // Render the Camel... }    
};
...
class Car
{
public:
   void render(Renderer& r) { r.render(*this) };
   ...
}

class Truck
{
public:
   void render(Renderer& r) { r.render(*this) };
   ...
}

class Camel
{
public:
   void render(Renderer& r) { r.render(*this) };
   ...
}

Note that should you want to render the stuff in some other way the objects themselves are unaffacted, you just change the implementation of the Renderer.

For more elaboration on this kind of structuring check out the design pattern called "Visitor".




/Per

&quot;It was a work of art, flawless, sublime. A triumph equaled only by its monumental failure.&quot;
 
Thanks so much guys! This was probably (hopefully) the last major road block in my engine design (At least until the netcode, ughhh). LOL! Camel? How random, I love it. I'm going to put a camel in my game just because that soo cool!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top