Baron of Hell
Register | User Profile | Member List | F.A.Q | Privacy Policy | New Blog | Search Forums | Forums Home
Doomworld Forums : Powered by vBulletin version 2.2.5 Doomworld Forums > Misc. > Everything Else > Quasar's C++ Corner
 
Author
All times are GMT. The time now is 19:42. Post New Thread    Post A Reply
Quasar
Moderator


Posts: 4615
Registered: 08-00


Here is a neat thing you can do which, oddly, I cannot find any references about on the Internet.

In Smalltalk and Objective-C, it is possible to forward messages (aka method calls in C++) to other objects if the current object is incapable of handling them itself. This is a process called delegation.

C++ doesn't have any language features that seem deliberately designed for the express purpose of delegation, but it does have one that can be co-opted for it. Here's a brief demonstration.

code:
class SomeOtherType { protected: int b; public: void foo() { printf("foo\n"); } int getB() { return b; } }; class SomeClass { protected: SomeOtherType containedObject; public: void doStuff() { printf("Hi!\n"); } SomeOtherType *operator -> () { return &containedObject; } }; int main() { SomeClass baz; // I can call the class's own methods normally... baz.doStuff(); // But if I invoke operator -> , the "message" I send // is forwarded to a different object; in this case, // it goes to the containedObject of type SomeOtherType. baz->foo(); int x = baz->getB(); return x; }

The one shortcoming of this against true delegation / message forwarding is that it's difficult to conditionally forward to different objects. This does however seem like an extremely useful alternative to multiple inheritance where you only need to combine the interfaces of two otherwise disparate classes (and especially when they share the same base class, and therefore the grotesqueries of virtual inheritance would be invoked).

What do you think about it?

Old Post 01-28-12 01:50 #
Quasar is offline Profile || Blog || PM || Email || Homepage || Search || Add Buddy IP || Edit/Delete || Quote
Maes
I like big butts!


Posts: 8662
Registered: 07-06


Uhmmm... I'm not impressed. It seems to me that you waste the operator overload by hardwiring it to one specific type of object/action.

If the purpose was to have a class do something that may be common/expected of other classes, there are other design patterns such as Inversion of Control or Visitor which handle it better.

Well..."better" is very relative. This sort of design is better suited to "enterprise" systems which can literally make no sane assumptions about legibility or optimization, in the face of ever-changing specs. IMO they both lead to fugly code but are a more general solution to the problem you posed.

Old Post 01-28-12 02:04 #
Maes is online now Profile || Blog || PM || Homepage || Search || Add Buddy IP || Edit/Delete || Quote
shadow1013
Junior Member


Posts: 228
Registered: 08-10


Meh, honestly I hate C++ and prefer C itself or Objective-C. I always find it too bloated

Old Post 01-28-12 02:26 #
shadow1013 is offline Profile || Blog || PM || Email || Search || Add Buddy IP || Edit/Delete || Quote
Quasar
Moderator


Posts: 4615
Registered: 08-00



Maes said:
Uhmmm... I'm not impressed. It seems to me that you waste the operator overload by hardwiring it to one specific type of object/action.

If the purpose was to have a class do something that may be common/expected of other classes, there are other design patterns such as Inversion of Control or Visitor which handle it better.

Well..."better" is very relative. This sort of design is better suited to "enterprise" systems which can literally make no sane assumptions about legibility or optimization, in the face of ever-changing specs. IMO they both lead to fugly code but are a more general solution to the problem you posed.


Replace my one object with a virtual base class that can be inherited from by any number of objects, then. Say that the particular instance it is set to can be selected and is remembered as state. Whatever. Even a series of totally unrelated types could be returned by the operator function. The problem, as I mentioned, is that you cannot select the destination object *at* the point of call, as you can in Objective-C.

Don't criticize the concept solely on a simplistic example. It was meant to be illustrative, not holistic.

Old Post 01-28-12 02:36 #
Quasar is offline Profile || Blog || PM || Email || Homepage || Search || Add Buddy IP || Edit/Delete || Quote
andrewj
Senior Member


Posts: 1380
Registered: 04-02


I think overloading certain operators, -> for one, just makes for code that's harder to read. Normally if you see "baz->foo()" you'd think the foo() method is being called on a baz object, and this kind of thing subverts that expectation, so that's why I wouldn't use such a construct.

Old Post 01-28-12 02:58 #
andrewj is offline Profile || Blog || PM || Search || Add Buddy IP || Edit/Delete || Quote
Quasar
Moderator


Posts: 4615
Registered: 08-00



andrewj said:
I think overloading certain operators, -> for one, just makes for code that's harder to read. Normally if you see "baz->foo()" you'd think the foo() method is being called on a baz object, and this kind of thing subverts that expectation, so that's why I wouldn't use such a construct.

What about when it's what you need to happen?

The problem in particular that I am looking for a solution to in Eternity at the moment is that I want to be able to store qstrings inside MetaTables. In order to do that I need a qstring-containing object derived from MetaObject.

However, I would like to have direct access to all of qstring's 56 methods and not have to jump through an accessor to get to them. I would, if it were not a nightmare, like the MetaObject descendant MetaQString, to behave as if it "is a" qstring.

However, doing that via multiple inheritance, which would be your first instinctual suggestion, would lead to a hideous problem - both MetaObject and qstring share a common base class - they are both ZoneObjects. This would necessitate virtual inheritance, which would, amongst the other problems it creates, make the use of static_cast alongside MetaObject's custom RTTI illegal. The current idiom looks like this, and would be blown to hell:
code:
while((obj = meta->getNextType(obj, METATYPE(MetaString)))) { // I KNOW it is a MetaString; this is safe. MetaString *str = static_cast<MetaString *>(obj); ... }

I wish to avoid multiple inheritance always. I think it leads to bad things in pretty much any situation.

Old Post 01-28-12 03:26 #
Quasar is offline Profile || Blog || PM || Email || Homepage || Search || Add Buddy IP || Edit/Delete || Quote
fraggle
Super Moderator


Posts: 6000
Registered: 07-00


Neat trick, although a bit too "clever" for my liking. To me, this sort of demonstrates how C++ got operator overloading wrong: it shouldn't even be possible to overload operators like ->.

Worth pointing out as well, this still misses a lot of the usefulness of delegation, because in Objective C you can use it to do things like RPC calls, and have your method call forwarded to another machine. You can't really do that here without some kind of code generation tool.

Old Post 01-28-12 12:06 #
fraggle is offline Profile || Blog || PM || Email || Homepage || Search || Add Buddy IP || Edit/Delete || Quote
hex11
Senior Member


Posts: 1482
Registered: 09-09


Grotesqueries of inheritence? Not sure what you mean (not very fluent in C++) but I would have figured that in general it's simpler to just subclass and let inheritence take care of calling one of the parents' method?

Old Post 01-28-12 13:21 #
hex11 is offline Profile || Blog || PM || Search || Add Buddy IP || Edit/Delete || Quote
Quasar
Moderator


Posts: 4615
Registered: 08-00



fraggle said:
Neat trick, although a bit too "clever" for my liking. To me, this sort of demonstrates how C++ got operator overloading wrong: it shouldn't even be possible to overload operators like ->.

Worth pointing out as well, this still misses a lot of the usefulness of delegation, because in Objective C you can use it to do things like RPC calls, and have your method call forwarded to another machine. You can't really do that here without some kind of code generation tool.


Actually the main use for overloading operator -> is usually for supporting "smart pointer" classes. In those implementations, they do almost literally the same thing I am doing here: redirect the access to the object to which they internally point.

STL iterators, which either are pointers, or act like pointers depending on the implementation, generally also have it (as well as a unary operator *).

hex11: I said virtual inheritance. Look it up. It's not a good thing in general - it requires modification of your class hierarchy all the way up to the root in order to avoid duplication of instances inside a class that inherits from them more than once, requires dynamic_cast to be used, and makes your program slower.

EDIT: Here is a more concrete idea of what I have in mind:
http://eternity.mancubus.net/text/m...ringptr.cpp.txt

Last edited by Quasar on 01-28-12 at 18:43

Old Post 01-28-12 17:09 #
Quasar is offline Profile || Blog || PM || Email || Homepage || Search || Add Buddy IP || Edit/Delete || Quote
All times are GMT. The time now is 19:42. Post New Thread    Post A Reply
 
Doomworld Forums : Powered by vBulletin version 2.2.5 Doomworld Forums > Misc. > Everything Else > Quasar's C++ Corner

Show Printable Version | Email this Page | Subscribe to this Thread

 

Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is OFF
vB code is ON
Smilies are OFF
[IMG] code is ON
 

< Contact Us - Doomworld >

Powered by: vBulletin Version 2.2.5
Copyright ©2000, 2001, Jelsoft Enterprises Limited.

Forums Directory