|
I use MI, for exaple, for transform an win32 app in win nt service. (Note, the nt service class is not develope for me).
May be you think "He is crazy", but i'm not the only one.
|
|
|
|
|
i usually have to go wash up afterwards.
i used to feel this way about STL, but i got over my shame and now i enjoy it - right out in public, sometimes. i encourage everyone to try STL, templates and MI, at least once. but you should avoid VB - the shame of VB never goes away and the smell can't be washed off, no matter how much soap you use.
-c
Smaller Animals Software, Inc.
You're the icing - on the cake - on the table - at my wake. Modest Mouse
|
|
|
|
|
Hey !
MI, is ok in some cases, take a look at the book "Design Patterns", you will find lot of very good stuff that couldn´t be so well implemented without using MI.
Bye !
Braulio
|
|
|
|
|
I use ATL all the time too, but where it really comes in handy is with WTL.
If you have a standard dialog and need ...
Scrolling support? CScrollImpl
Resizing? CDialogResize.
Menu and toolbar updates? CUpdateUI.
DDX support? CWinDataExchange.
I think it's intuitive and natural to use MI and mixin these classes to add additional functionality. I've written my own mixin classes that add additional custom functions to WTL's CHyperLink.
I can't understand the brain-dead arguments against MI. Frankly, if you get yourself into a diamond pattern with MI, you're an idiot. It's just not that hard.
CodeGuy
The WTL newsgroup: over 1300 members! Be a part of it. http://groups.yahoo.com/group/wtl
|
|
|
|
|
I agree with you mixin classes as implemented by WTL are a superb example of use of MI. In fact, IMHO mixin assembling is the best single feature enabled by MI.
Frankly, if you get yourself into a diamond pattern with MI, you're an idiot
Well, for mixin hierarchies not based on message dispatching (as ATL/WTL) but rather on virtual functions, virtual derivation (and thus diamond pattern inheritance graphs) are a must.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|
Guess I should be more clear on my rant.
WTL shows that MI is very appropriate where the classes you're inheriting from are orthogonal in nature (which is the definition of mixin). If you are doing inheritance where you clearly start to have conflicts due to overlap, then you probably need to take a serious look at your class hierarchy because you're doing something very wrong.
I used the diamond pattern as an example, because this is the one that all the critics use to say "oh look, MI is terrible. it's so confusing". Well, yes, if you are trying to combine classes with similar functionality, you're asking for it.
Basically, you can contrive anything to prove a point that "MI is bad" (as the Java people do), but really the concepts involved in creating a good MI hierarchy are straightforward and more intuitive than the alternatives.
CodeGuy
The WTL newsgroup: over 1300 members! Be a part of it. http://groups.yahoo.com/group/wtl
|
|
|
|
|
Any real world examples on how you use MI?
Apart from ATL, I can't think of a single time in the last five years that I've used multiple inheritance.
Michael
|
|
|
|
|
Actually, I used it once in a project where I had to extend both CPropertyPage and CDialog to do some special processing. It was either that, or duplicate a bunch of code in both classes.
Or convert all the dialogs to property sheets.
Winning isn't everything, but then, losing is nothing.
|
|
|
|
|
here's one i've used a few times:
i have a dialog class (CMyDlg) that uses some other class to do some processing. if that processing takes a long time, it's nice to show a progress dialog. but, only the worker class knows the progress status, so i need a way to get that info back to the dialog. in C, i'd just use a callback function (but in C++, that's not nice).
so, i make a little class like this:
class CProgressSink
{
public:
virtual bool Progress(int iCurrent, int iTotal) = 0;
};
and i multiply inherit my dialog class from CProgressSink, implementing the Progress function to do whatever progress updates i need (update a progress bar, show some text, pump some UI messages, etc).
bool CMyDlg::Progress(int iCur, int iTotal)
{
TRACE("%d of %d\n", iCur, iTotal);
return true;
}
at the same time, i've told my worker class to accept a pointer to a CProgressSink as a parameter in one of its ctors:
class CMyWorkerClass
{
CMyWorkerClass (CProgressSink *pSink = NULL) {m_pSink = pSink;}
};
when i create the worker class object in CMyDlg, i can tell it where to send its bloody progress messages:
CMyWorkerClass thingy(this);
so when the worker class is working, it tests to see if it has a valid CProgressSink pointer. if it does, it calls CProgressSink::Progress with the current progress state.
the nice thing about this is that if i want to use the worker class from some other class (another worker class, for example), i just inherit that new class from CProgressSink and tell the worker class that the new class wants to be notified of progress events.
you could make CMyWorkerClass take a reference (or pointer) to a CMyDlg class, instead of adding the CProgressSink class. but that means you can only send Progress events back to CMyDlgs. while, for not much more work (like 5 lines more), you get the flexibility to send progress state to any class you can create.
now, some people would do this with a worker thread, but i think that's overkill in many cases. you could also do this with a C callback function (passing a "this" pointer around), but that's a bit scary.
-c
Smaller Animals Software, Inc.
You're the icing - on the cake - on the table - at my wake. Modest Mouse
|
|
|
|
|
I've used it in our current project. I've implemented a scripting engine so that users can write Python scripts to automate the application. Since the data access speed is very slow in Python compared to compiled code, I've also provided the ability for users to write DLLs that implement commands accessible from Python through the application.
In my implementations, objects accessible through Python are derived from CPythonObject (my own). Objects accessible through the DLL command extensions implement a custom interface (non-COM) called I<something>.
For instance, I have an "area" object accessible to both Python and the DLL interface. The CArea object is derived from CPythonObject and IArea.
I think that there is a time and a place for MI. You just have to recognize the need.
J
|
|
|
|
|
Maybe I'm in the minority, but I use MI very often. Here's a simple example:
My apps often serialize various kinds of objects which eventually need to be presented to and manipulated by a GUI, typically tree and list controls. The objects are uniquely identified by id's (which happen to be unsigned longs, but that's immaterial) and also have non-unique names.
These objects multiply inherit from IIdentifiable and INamed , which are "interfaces" (i.e. classes with no data members, and whose methods are all pure virtual). My GUI elements know how to display any kind of INamed object because they can get athe object's name by calling getName() . The item data field of each GUI element stores the object's id, retrieved via getId() which is a method of IIdentifiable .
While C# and Java may not allow multiple inheritance, they allow objects to implement any number of interfaces, which is a safe way of exposing multiple behaviors. This is what I've done in the above C++ example.
One should exercise caution before settling on one side of the fence over questions like "do you use MI?" and "do you use goto s". Both concepts can be both used and abused.
/ravi
"There is always one more bug..."
http://www.ravib.com
ravib@ravib.com
|
|
|
|
|
Hi,
There is a classic C++ book, called "Desing Patterns", there you can find quite good patters that work pretty cool with Multiple inheritance, and add real power to your code.
Greetings
Braulio
|
|
|
|
|
I see 15 people so far have said they intentionally avoid it. Why? Is there something bad about MI?
- Matt Newman
-Sonork ID: 100.11179:BestSnowman
†
|
|
|
|
|
I think there is some kind of thinking among certain people that MI breaks the OOP concept.
Nish
My miniputt high is now 29
I do not think I can improve on that
My temperament won't hold
www.busterboy.org
|
|
|
|
|
I think many folks have an issue dealing with virtual base classes and method name clashes.
I dont have any problem with them and use them extensively. Perhaps because I have no choice because ATL is based on MI.
I used to code a lot in Java. One of the things I hated about Java was the lack of MI. If you had a CFeline and a CWild, it seems natural that CTiger would inherit all the properties of CFeline and CWild, and hence MI from the two classes.
With Java and C# you would have to use interfaces (or the C# equivalent), but that is painful and not very intuitive to me.
|
|
|
|
|
MI can result in hard to maintain code if used naively, and can result in easily extensible (and thereby manageable) code if used properly. Here's a nice discussion on the subject.
/ravi
"There is always one more bug..."
http://www.ravib.com
ravib@ravib.com
|
|
|
|
|
|
And I was the first to vote that way I guess it pays being up late at night at whatever time it happened to be.
James
Sonork ID: 100.11138 - Hasaki
"Smile your little smile, take some tea with me awhile.
And every day we'll turn another page.
Behind our glass we'll sit and look at our ever-open book,
One brown mouse sitting in a cage."
"One Brown Mouse" from Heavy Horses, Jethro Tull 1978
|
|
|
|
|
The real truth is that MFC says "we don't use it" and all other people therefore don't use it, because:
a) what MFC says, must be correct or
b) otherwise they would write code that does not work with MFC anymore.
--
See me: www.magerquark.de
|
|
|
|
|
|
Really? at which class should I look, to see it?
(or do you mean "derive from CWnd AND nothing else" counts already as mutliple inheritance? )
--
See me: www.magerquark.de
|
|
|
|
|
|
Because you need information about the inheritance tree in order to make sure it works . Such information is not always available , and can be a real bugger to debug if and when MI eventually kicks you in the ass. If you have complete control of all source in a project then there is a case to use it .(I'm ignoring pure virtual base classes used as interfaces, where it is useful and safe ). However if you have complete control , then why not design so that MI is not needed and hence make debugging easier for those who come later ?
|
|
|
|
|
There are a lot of ideosyncracies about MI that can make it difficult to use and maintain. Since I have about 12 years or so of C++, I have used MI quite a bit. However, I only use it for my own personal projects. In situations where I'm consulting or programming for someone else where I don't know who will eventually maintain the code, then I shy away.
By the way, you'll notice that the C# design team intentionally left this feature out (as did the Java team I believe).
Cheers,
Tom Archer
Author, Inside C#
|
|
|
|
|
I don't mean to begin a flame war here, but... Suppose in a high-level design you come with some C tha IS-A A and a C . If you're programming for someone else, would you prefer explaining to her about the standard artifact in Java/C# for dealing with such situation (namely derive from an interface and delegate to a private member)? Is this more intuitive/maintainable than multiple derivation?
Seriously, MI is not such a common pattern, and can lead to obfuscated design, but when it is the appropriate thing to do it can save your life. It goes along with C++ philosophy of treating programmers as grown adults and let them have access to all the tools available, dangerous as they may be.
I know you're a C# guru, so I'd like to know whether there is a pragmatic reason for leaving MI out of this language. Does it make reflection or some other feature harder to implement? That could be a reasonable case against MI.
Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo
|
|
|
|
|