• Advertisement

Archived

This topic is now archived and is closed to further replies.

Object Oriented Programming

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have read several books on C++ and the Object Oriented programming paradigm and while I understand the necessity of using a data driven design, I still fail to comprehend why I would ever need to implement a pure virtual base class like CObject that has absolutely no code associated with it. Could somebody who knows please explain this? Paradigm Shift 2000

Share this post


Link to post
Share on other sites
Advertisement
Why? To define properties and methods which are common to all the classes in your class hierarchy. Java is a good example. The Object class defines such methods as clone(), toString(), equals(), and hashCode(). Because everything extends Object, you know that you can always use these methods.

Anyway, that''s what I find useful about it. The OO Gurus can probably offer you a better explanation.

~~~~~~~~~~
Martee

Share this post


Link to post
Share on other sites
So that code which requires one of a number of object types can have a uniform interface. If you have the base class "Parent" and the derived classes "Derv1", "Derv2" and "Derv3", if your code is applicable to any of Derv1, Derv2 or Derv3, a pure virtual base class allows you to employ any of them in your code and be sure that you are referring to an instantiated object.

Pure virtual objects can never be created, so that relieves you from wondering whether the object you''re about to work on is defined or not.

Share this post


Link to post
Share on other sites
The whole idea of OOP is to encasulate your code and decouple it from your logic. Doing this promotes reuse and makes you code easier to understand and debug.

In C you would have to do something along the lines of this:

for(int i=0;i drawEnemy(enemy);

for(int i=0;i drawMissile(misiles[i]);

for(int i=0;i drawPlayer(players[i]);
etc...

As you can see each objects needs a draw function that would have to know how to draw the data to the screen. Using OOP all your objects could draw themselves by having a base class or an interface with the draw method in it and just extend that class and overide the draw method or implement the draw method (in the case of virtual/interface)

then your code could do this :

for(int i=0;i gameObjects[i].draw();

That''s the idea. There are plenty of resources on the web and in the book store that can help you understand OOP. Believe me, once you understand the principles you will be amazed at how much faster you can code once you have a good design. You will also find yourself coding less and actually reusing code too!

Share this post


Link to post
Share on other sites
Encapsulating data and methods into a class makes sense. I''ve built container classes before, especially for file loaders where I want to insulate myself from that messy code for loading image files in. But I still don''t understand why I would need to derive these containers from a pure virtual class. Like for instance: Why would I want to define a pure virtual class with place holders for void LoadFile(const char * filename) and void UnloadFile(void) and subclass file loaders from this, overriding the LoadFile() and UnloadFile() methods with code specific to each file type, when I could just create a new class for each different file type because ultimately, the data and method of retrieving the data for each file type is going to be different. I''m going to wind up redefining the entire class after subclassing it anyway. So, like I said, why should I want to do something like this?

Paradigm Shift 2000

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Ok, I learned polymorphism by example. One of the best examples i''ve seen was with a paint program that I had to do at school.

In my paint program, I needed a way to draw and undo paint objects. The objects that I supported were :
1.) a point
2.) a line
3.) a box
4.) a circle

Now, say that you wanted to keep track in which order the items got drawn, as this is extremely important. You would need to store each item in a list or vector. ( i''m referring to the stl::list and stl::vector classes ) If I did not use polymorphism, i would have to keep a separate list for each object type, or I would need to implement each type of object with a switch statement in my main implementation class( this is not good as it would require a lot of maintenance and changes to your main drawing code everytime you needed to implement a new type, this would work, but the implementation is not very clean and maintainable.) Now say that you want a way to undo the objects in the list, how do you maintain order? You can do it, but again, it would be difficult.

A clean implementation uses polymorphism.

I created a base virtual class called CShape
CShape had methods like Draw(), Undo()
CShape had attributes like XPosition, YPosition

I then created an implementation class for each type of object that I want to support, so I created a CLine : public CShape
CPoint : CShape
CBox : CShape
CCircle : CShape

I then created one list to store all objects drawn
std::list

Now, I can easly iterate through the list calling the Draw method on all objects. I let polymorphism decide if it should draw a point, line, box or circle.

If I need to add a new drawable object, I can easly add a new implementation object without impacting my main drawing routines and undo routines.

CShape *NewObject = CLine();

// This method actually calls the draw method on CLine and not CShape;
NewObject->Draw();

// Add your new object to the object list
ObjectList->insert(NewObject);

Does this make sense?
This is hard to explain in writing.

In your example of file loader, I have a base FileDecoder class, I then have implemented a decoder class to support .bmp, .jpg, .gifs. It really doesn''t matter to my graphic engine which type of format I want to support, the graphic engine only cares about a Direct X Surface.

Poylmorphism is one of the hardest to grasp..A lot of new c++ developers sometimes make mistakes as referring to it as function overloading, which is not the case, what so ever.

Polymorphism guarantees that by calling a virtual method on a base class, that it will call the correct method for you.

Alek

Share this post


Link to post
Share on other sites
Hmm.. So then that means, say i made a pure virtual base called CFile, and derived 4 file loaders from them
CBmp : public CFile
CWav : public CFile
CJpg : public CFile
CTile : public CFile

and I did something like this:

CFile file("blah.bmp");

It would automatically use my CBmp class instead of one of the other 3?

Paradigm Shift 2000

Share this post


Link to post
Share on other sites
Close,

You can not directly instantiate a pure virtual base class. You would need to create an instance of a derived class and assign it to a pointer of the base class.

You would do the following:


  
// This constructs a CBmpFile object, and assigns it to File

CFile* File = CBmpFile();

// Now Execute the Virtual Methods

File->Load(FileName);

// Finished with the file, so release

File->Close();



Does that make sense?

Alek

Share this post


Link to post
Share on other sites
Abstract base classes can also be known as "Interface classes"; specifically, a base class with only public members, no implementations (all pure-virtual functions) and no data members can be called an "interface". This is extremely useful when you want to separate implementation from interface, and greatly helps decoupling code.

Example: an IQueue interface might give you functions like open, get, put, waitForData, etc. IQueue derivatives are forced to implement these functions--say a SocketQueue, FileQueue, etc. An application would see these only as IQueues, and would have no need to know about whether they were dealing with Sockets or Files, and would not have to recompile every time SocketQueue or FileQueue changed.

Game Example: IPlayer could be used as a base class for LocalHumanPlayer, RemoteHumanPlayer (e.g. network), and ComputerPlayer. The game engine only sees IPlayer--it does not need to recompile every time any of those derived classes change.

In other words, a class like this describes a protocol or contract that clients of derived classes will stick to. Derived classes must implement the functions given, guaranteeing they''ll be there.

Share this post


Link to post
Share on other sites
Oh, I see now, I think. Just as an example because this would be completely useless in practice but basically, what you''re saying is that if I made a pure virtual base class like CFile, and gave it a virtual void Load(const char * filename) function, any derivation i make like CBmp : public CFile *must* define a void Load(const char * filename) function otherwise the compile will error out. Then, I could use in my code CFile * bmpfile = new CBmp; bmpfile->Load("foo.bmp") and it would always use the proper Load() function without recompiling even if I modified the code for void CBmp::Load(const char * filename)? Would I then need to implement this type of class in a DLL(which is what I''m currently doing with my file loaders so I don''t need to recompile all my projects whenever I need to fix a bug in the loader code)?

Paradigm Shift 2000

Share this post


Link to post
Share on other sites
quote:
Original post by Paradigm Shift 2000
what you're saying is that if I made a pure virtual base class like CFile, and gave it a virtual void Load(const char * filename) function, any derivation i make like CBmp : public CFile *must* define a void Load(const char * filename) function otherwise the compile will error out.


That is correct.
quote:

Then, I could use in my code CFile * bmpfile = new CBmp; bmpfile->Load("foo.bmp") and it would always use the proper Load() function without recompiling even if I modified the code for void CBmp::Load(const char * filename)?


Any call to bmpfile->Load would call CBmp::Load, because bmpfile is-a CBmp (though it looks like a CFile). However, this function _would_ need to recompile because of the "new CBmp". Since you'd be calling the CBmp::CBmp constructor, this module would be sensitive to the changes in CBmp implementation file. However, anything else that calls through bmpfile only relies on CFile, not on CBmp. This is why you usually physically separate the part of the code that allocates objects from the code that uses those objects if you're using the interface pattern. Usually, there's a "factory" class that generates the objects (has all the calls to new) and returns CFile, making clients of that class completely oblivious to CFile derivatives. It's just that every time a derived class changes, the factory class must recompile; but that's better than having your entire engine recompile.

quote:

Would I then need to implement this type of class in a DLL(which is what I'm currently doing with my file loaders so I don't need to recompile all my projects whenever I need to fix a bug in the loader code)?



You could do it either way--in a DLL or in your main executable. One doesn't dictate the other. But if you wanted to patch the CBmp implementation without having to patch the executable, doing it in a DLL would solve that problem.

Edited by - Stoffel on September 24, 2001 11:40:40 PM

Share this post


Link to post
Share on other sites
You''ll want to use a pure virtual class to represent abstract concepts. For a silly example, Food is an abstract concept, we know that we can do certain things with food (like eating it) but there''s not too many other information we can put into our food class & still retain generality. So we can make Food have a virtual Eat() function, then all food objects can inherit from Food & we know how to Eat() any object. You use pure virtual functions when you want to define interface without defining any kind of implementation. As a side note I try to write C++ in a Java style, only inherit from one base class that has defined functions, all other inheritance must come from Abstract Base Classes (ie all pure virtual functions). OO design is cleaner & there is usually no need for multiple inheritance and the evil that results from it.

Brad

Share this post


Link to post
Share on other sites
I think he finally got it!

Yeah. the biggest reason I use an abstract base class is so I can do stuff like this:

bool Road::add(Vehicle * vehicle);

This way, no matter what type of Vehicle I send it, when it comes time to draw the vehicles moving on the road, all I have to do is this:

void Road::draw()
{
for (j=0; j < vehicleList.length(); j++)
{
vehicleList[j]->draw();
}
}

And it would know exactly which version of draw() to call--be it truck, car, van, or motorcycle--because draw() is virtual . And because add() takes a pointer to an abstract class, I can send it any of its derived classes, instead of creating multiple overloaded versions of add().

And of course, sometimes I do it just for the heirarchy.

Jinushaun

Nation Leprechaun

Edited by - jinushaun on September 25, 2001 12:34:30 PM

Share this post


Link to post
Share on other sites
Oh! I don''t know why I didn''t see it before, because now it seems so obvious. I could say, define in a DirectDrawObject class a void LoadResource(CFile * file) function, and then use file->Load(filename) and it would always use the right Load() function, without me having to overload the LoadResource() function for each different type of file. That would be *so* useful!

Paradigm Shift 2000

Share this post


Link to post
Share on other sites
Just wanted to say that the base class doesn''t have to be entirely pure. You can mix non-pure member functions with pure except you can''t create an object out of that base class. But if you derive from the base and create a base pointer and assign a derived object''s addy to it then the base member function code still gets executed but parts of derived object''s code also is executed within the base. So your base could crunch code and be like a high level platform while under it is specific code the platform uses i.e. derived object''s code. Don''t forget to make your destructors virtual. When I started c++ I used to think in terms of having an interface without any code and then implement that code in derived objects but try to put majority of common code in the base and see what you get

Share this post


Link to post
Share on other sites

  • Advertisement