Modular classes article sucks
quote:
This is a big pain in the ass and its impossible to have private and protected struct members.
Its possible to simulate this IF u really wanted by using compiler directives.
-----------------------------
-cow_in_the_well
http://cowswell.gda.ods.org/
-----------------------------
A wise man once said "A person with half a clue is more dangerous than a person with or without one."
Maybe the next part of the series has some useful informations ?
Maybe we all misunderstood the point of it, dunno...
Tim
--------------------------
www.gamedev.net/hosted/glvelocity
glvelocity.gamedev.net
www.glvelocity.com
Edited by - tcs on June 26, 2000 8:01:05 PM
I think it should be noted that there is _more_ than one way to accomplish OO aspects in a non-OO language, especially C. I also have you know that this is not totally useless. Here is a specific applications: platforms(especially embedded systems) where a C++ compiler is not available.
Something that I do which was not really mentioned in the article is a case of single inheiritance. Example:
typedef struct baseclass {
int x;
int y;
} BASECLASS;
Derived class:
typedef struct newclass {
BASECLASS parent;
int z;
} NEWCLASS;
Now here is where it has power: A pointer to newclass can be typecast to a pointer to baseclass without ANY issues. The compiler formats the beginning of NEWCLASS structure the same way it formatted BASECLASS in memory, therefore any code that uses BASECLASS can work with NEWCLASS(unless you modify the behaviour, but the whole idea is NOT to do so).
About the global table of instances of objects: it was a neat idea, I always make a pointer to the "object" an additional argument to the function thus avoiding all issues his technique creates. Actually I believe C++ implements it closer to my way, it passes an additonal hidden argument in functions which is a pointer to the instance of the class being called.
Someone mentioned COM. Well, technically a COM interface is array of pointers to functions. Needless to say, C function pointers have a great deal of power, and it would be possible to use this as well, here''s an example.
About three years ago, I was working on my 3d engine, when software rendering was still an option, and Glide was still a pretty good choice. I used a set of function pointers to a base triangle drawing function. This pointer was set at the initialization to either the software rasterizer, or glide rasterizer. Anytime a triangle needed drawing, this pointer was used, eliminating the need for a test everytime to determine the triangle drawing routine. Another case: I wrote a parser for HTML, and decided that I would have a general tag processing function, so I made a hash table of pointers to functions, hashed by tag name, and then as I parsed the file, I simply looked up the tag name in the table and called the function I found. When I need to add a new tag, I just add a call to add it to the table in the parser initialization, and then write the functions.
Of course, if I wanted to use a OO language, I could, but there is also another benefit to using a language like C: experimenting with techniques for OO stuff NOT available in your language. Guess what, your OO language is not completely OO, nor is it the only approach to OO, but because it has certain attitudes and decisions in its approach your limited by that. I my procedural language I can write OO code unencumbered by the decisions of the designers of C++ or Java, and can experiment with techniques that you may find in your NEXT OO language.
I didn''t mean that as a rant, but I just wanted to point out something other than what he talked about, and techniques I find useful. Hey, here''s a PRODUCTIVE idea, lets turn this thread into a discussion of techniques rather than flamebait and making fun of the guy who wrote the article.
I was very interested in reading the article at first.
Being able to create an easily usable inheritance model with encapsulation without using built-in C++ stuff would be great in some cases.
But the article just had arrays of members that are statically allocated and this is just plain wasteful.
I agree with the guy who has a struct with a pointer to the base struct. Thats what I did before I learned C++.
My whole point was that I was creating some of the basic C++ oop technology with structs and function pointers and when I realized how easy C++ is and that it allows more typechecking and is easier to read I just decided to use it.
It makes your skills more marketable to companies using these technologies too. Why learn something or create something that no one ever uses?
The way I use OOP is to define large classes which expose limited functionality like sprite classes with simple methods like stepAnimation() setAnimation(int animIndex) and render() or load(char *fileName) and subClass from there once or maybe twice but no further.
Some people use objects for everything and that is wasteful. For example have a C3DObject class with an array of pointers to VertexBuffers instead of using template classes. Its faster.
MCSE, MCSD, Sun Certified Java Programmer
Pimp Daddy ;)
Learn a new language every year
If you stick to just one language your limiting your problem solving skills.
Like the saying goes: "if your only tool is a hammer, every problem is a nail".
Isn''t Quake III all written in C ( with few parts of ASM ) ? Are you saying Quake III technically sucks ?
I always thought there is no ultimate language. Some are better than others for specific applications, but they''re all tools. You can make good code in C and bad code in C++, or the opposite. None is better. They''re simply *different*, and that''s my point. If you want to do OOP, you''ll sure prefer C over C++, but nobody wants to use OOP nowadays.
Y.
quote:
If you want to do OOP, you''ll sure prefer C over C++, but nobody wants to use OOP nowadays.
I think you confusing OOP with procedural programming.
OOP == Object oriented programming, which is why one would use C++ over C. Not the other way around.
So what you probably meant was this:
"If you want to use procedural programming, you''ll sure prefer C over C++, but nobody wants to use procedural programming nowadays."
Of course, I disagree with that last segment. I use OOP quite often, but for small tools procedure programming is usefull.
----------------------------------
"Death has come to your tea cup."
Yes, I agree that some of the methods outlined in the article could be described as clumsy, and that to an C++ OOP programmer would seem ugly and disfunctional, but that isn''t what the author set out to do was it? - he/she set out to show a way in which modular programming could be achieved without the use of classes. The author achieved at least part of this goal, it may not have been the best way, it may not have been what some people were looking for, but at least the guy tried, and I cannot fault them for that.
-Mez
I''m also horrified by DogFood''s post:
quote:
Something that I do which was not really mentioned in the article is a case of single inheiritance. Example:
typedef struct baseclass {
int x;
int y;
} BASECLASS;
Derived class:
typedef struct newclass {
BASECLASS parent;
int z;
} NEWCLASS;
Now here is where it has power: A pointer to newclass can be typecast to a pointer to baseclass without ANY issues. The compiler formats the beginning of NEWCLASS structure the same way it formatted BASECLASS in memory, therefore any code that uses BASECLASS can work with NEWCLASS(unless you modify the behaviour, but the whole idea is NOT to do so).
Sure, this will get you to inherit members of the base class, but it has several problems:
1) It obfuscates what you''re trying to do. Good luck getting this past code review.
2) I''m pretty sure this will throw compiler warnings (explicit conversion to incompatible type). Where I work, we have a 0 warning tolerance.
3) Common members are not the realy power of inheritence. The power comes in with member function inheritence.
It seems that many people are confused about what problem inheritence/polymorphism is supposed to solve. The problem is this:
// cumbersome type checking
struct Object
{
int type;
// common members, i.e. position, size, whatever;
};
void display_object (Object* pOb)
{
switch (pOb->type)
{
case TYPE_CIRCLE: // do one thing
case TYPE_SQUARE: // do another thing
}
}
In your main loop, you would iterate through a list of Object pointers, and for each call display_object (pOb). This is a prime candidate for polymorphism:
class ObjBase
{
public:
virtual void display () = 0;
protected:
// common members
};
class ObjCircle : public ObjBase
{
// whatever you need in here
};
class ObjSquare : public ObjBase //etc.
Now, in your main loop, you iterate through your list of ObjBase pointers, and call pObj->display () for each, and they each do the right thing.
What''s been added? A vtable to store the function pointer to display (), and an extra indirection to call the function. What''s been lost? Well, you don''t need a switch, you don''t need to tag a type with each object. Probably a pretty even trade-off, both in instructions and memory.
How easy is this to maintain? You need to add your switch case to every function that switches on a type if you want to add or remove object types using the first method. For the second method, you just need to derive a new class.
I hope this has helped some people realize that polymorphism is not just "adding a dereference for no damn good reason to a function call". The example above is the issue for which polymorphism is the tool used to solve.
struct foo
{
int x;
int *y(void);
};
int init
{
struct foo bar;
struct foo baz;
(bar.y()) = (baz.y()) = &y();
}
Bang, you got a fast, slim, multiple instance of a data structure emulating class functionality. Of course, if you wanted private members you would need seperate modules and garbage, but that could easily be done.
-----------------------------
A wise man once said "A person with half a clue is more dangerous than a person with or without one."
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.