Qt vs MFC 126
Philippe Fremy writes: "I have just published and translated into English a comparison between Qt programming and MFC programming, which was written by Pascal Audoux (a fellow coworker). I am interested in feedback and would love to add quotes from developers that have used both toolkits." Here is the English version ("Qt vs MFC") as well as the French one ("Qt contre MFC").
Why is this on slashdot? (Score:1)
The conclusion drawn from our personal experience is obvious. Qt is far better than MFC. You'll produce better programs with less hassle.
I do agree though.
Re:Why is this on slashdot? (Score:2)
Very true. Literally within an hour or two, by following TrollTech's tutorial, a person can write and understand working GUI applications. One of Qt's strengths (and a tribute to its design) is how its learning curve is really quite low.
Re:Why is this on slashdot? (Score:1)
For simple applications, MFC's learning curve is also low - the wizard will generate all the glue code and provide
For an experienced Win32 programmer, MFC's learning curve is pretty much zero (flat?).
Re:Why is this on slashdot? (Score:1)
Qt doesn't need wizards, because the API really is quite clean. A person who has never programmed a graphical interface but knows C++ is good to go. The only real impurity in Qt is that the moc preprocessor needs to run as an extra step in the build. However, moc enables the rather simple signal and slot mechanism, which is intuitive and serves its purpose very well.
Create() and exceptions (Score:1)
Re:Create() and exceptions (Score:2)
#include <iostream>
#include <fstream>
#include <cstdlib>
int main() {
std::ifstream file("file.txt");
if(!file) {
std::cerr << "file.txt could not be opened for reading.\n";
return EXIT_FAILURE;
}
return 0;
}
Re:Create() and exceptions (Score:1)
Exceptions aren't the only way to report errors. Return values from a function is another way. Also using a global error object is another. Problem is in your example the program has no way to know why ifstream couldn't be created. Also ifstream has no way to communicate that to the program except through exceptions. That is because it uses its constructor to do it initialization. Since there are no exception handlers wrapping the creation of ifstream an exception would stop all execution of this program and the OS would provide a nice little popup to the user that makes no sense (on windows at least).
So next time...think about the code you are writting and why functions like Create() exist.
Re:Create() and exceptions (Score:2)
As far as ifstream is concerned, you can't tell *why* the file couldn't be opened because ifstream is abstracted that way. You could easily have some sort of "error state" (similar to badbit, eofbit, and failbit) which can be reported to the client only when the client asks for it. Simplest way I can think of to do that is with a get_last_error() member function that simply returns the error code of the last operation the object performed.
Sure, exceptions can be helpful in RAII, but they are by no means required by it. To assume so is not only incorrect, it diminishes C++'s lack of paradigm bias.
The only time I can think of when you're *forced* to propogate exceptions is when you have a polymorphic class whose base class's ctor throws. But then, you made a design decision to inherit from a class that throws.
Re:Create() and exceptions (Score:2)
Any subobject (base class or data member) that throws during construction will result in the object itself failing with an exception. You can wrap the c-tor's initialiser list in a function try-block if your compiler supports it, but that only allows you to change the type of exception thrown, not the fact that some exception is thrown. If you think about it, that's the only model that makes sense, and it's also very clean and tidy.
Re:Create() and exceptions (Score:2)
Re:Create() and exceptions (Score:2)
I think what you're trying to say is that if you don't want to allow a constructor to fail, you can change your design so that you can trap the exception that would be thrown by a base class or data member under normal circumstances. That's not what you actually said, though.
Of course, whether you want to have a design that carefully works around a system that's there for your own good is another question. Most of the time I've seen designs that went out of their way to ignore exceptions in a system that used them, the design was broken. Two-stage construction with Create() and Destroy() methods is a Bad Thing(TM) under almost all circumstances, and is responsible for more programming bugs in C++ than almost anything else I've come across (apart from naff use of pointers and arrays when smart pointers and container classes were the right tools for the job, of course).
Re:Create() and exceptions (Score:2)
I think we're pretty much in agreement, though. Don't know why anyone would go through all that trouble just to avoid a try block anyway.
Re:Create() and exceptions (Score:2)
OK, fair point, your change is implementation rather than design. And yes, we agree; exceptions and try-blocks are there for a reason, and it's usually easier to use them as they were intended than to fight against them.
wxWindows comparison... (Score:2)
Perhaps the most useful of all would be a comprehensive somparison of all the various toolkits/libraries.
Re:wxWindows comparison... (Score:1)
Re:wxWindows comparison... (Score:1)
"MFC programming", what the heck? (Score:2, Insightful)
Re:"MFC programming", what the heck? (Score:2, Insightful)
Could it be to support more than a single machine architecture? Windows NT used to run on Alpha boxes and now, the move to IA-64 means that an unsigned int is going to change size. They typedef everything to ensure that no matter what platform they move to, the framework doesn't require major changes.
Re:"MFC programming", what the heck? (Score:1)
Re:"MFC programming", what the heck? (Score:2)
It's this backwards compatablity that hampered MFC through too many years. Unfortunately, the only way to get rid of it now would be to start over (which will never happen now that
Re:"MFC programming", what the heck? (Score:1)
Re:"MFC programming", what the heck? (Score:1)
Could it be to support more than a single machine architecture?
I think also to support both 16-bit Windows and Win32 together, although that's more relevant for the base windows headers than MFC.
I don't mind a little opacity on the OS interface. And you often gain meaningful type names too.
(There are a number of examples on Unix, too: e.g. uid_t, pthread_t, etc. But certainly not to the same degree.)
Re:"MFC programming", what the heck? (Score:2)
uid_t and pthread_t are useful - they are the types used to hold a user ID or a thread ID. They can and do vary between implementations. Likewise types such as uint32_t and int_least16_t (from the C99 standard) are useful.
The WORD and DWORD types do not provide an abstraction and do not obviously have any particular numeric properties. I happen to know that the names WORD and DWORD come from x86 assembler and are signed 16-bit and 32-bit quantities, but a portable API should be using names like INT16 and INT32 for such types instead. Some of the other types are more reasonable, but the API is not that consistent.
All the pointer-to typedefs should be got rid of; they may have been somewhat useful under Win16 but are no longer relevant. UINT and ULONG are likewise fairly pointless.
In a few places the Win32 API could do with more use of typedefs, for example for process and thread IDs (currently DWORDs).
Review? (Score:1)
I always thought that comparisons had to be done with some kind of objectivity, if only for the purpose of decency... Apparantly this is not the case: MFC was produced by hordes of rabid monkees while God himself came down and Created Qt.
Even not a C/C++ developer myself, I don't see a lot of proof / illustration to the MFC side and way too much positive adjectives on the Qt side: "genious", "excellent",
The best one was probably:
"One of the stated goal of Trolltech is "The product and the documentation should be so good that no support is needed".
QED...
Qué?
Good conclusion, poor article (Score:5, Insightful)
Besides, it's really comparing apples and oranges. Anyone who's used the MFC at all knows that it's hardly OO. A much fairer comparison would be that of Qt to Borland's VCL. In many respects they're very, very similar, but it seems that the nod of more consistent OO design would go to the VCL. I base this mainly on the event-handling semantics of both toolkits. While Qt falls back to straight C (or possibly even a macro? shudder!) for connecting an event handler to a component, the VCL stays faithfully OO, implementing event handlers as method pointers (exposed as properties) on components.
Continuing the example used in the article, Qt reads:
connect( button, SIGNAL( clicked() ), SLOT( action() ) );
while the VCL would read:
button.OnClick = action;
Anyway, as I said, while I support the conclusion of the article, based on its lack of maturity I wouldn't use it to try to convert existing MFC programmers.
Re:Good conclusion, poor article (Score:1)
There are some comments in the Qt documentation [trolltech.com] why the approach isn't always strictly OO.
while the VCL would read:
button.OnClick = action;
Just curious: if button.OnClick and action are both method pointers, how can you have more than one action in response to a click?
Re:Good conclusion, poor article (Score:2)
> how can you have more than one action in response to a click?
Well, you're right, you couldn't in the current implementation. The simple method pointers on the components would have to be replaced by some sort of object with Add and Remove methods of its own, which would then insert the event handler assigned into some notification data structure. Basically you'd be "OO-fying" what connect() does in Qt. It would likely have more overhead than the Qt approach, so it's a matter of what you value more, OO-ness or performance.
Re:Good conclusion, poor article (Score:2)
Re:Good conclusion, poor article (Score:2)
> assignment operator (assuming VCL is in C++ [..])
It isn't, though, it's in Object Pascal, which doesn't support operator overloading. You could still do it by changing the event handler method pointers to pointers to a singleton object that did the same work as connect() via an Add() method, without incurring any memory overhead per event handler per component.
> you'd have to figure out how to make a semantically similar Remove()
Well, in C++ you could simply overload the following operators:
+= : add this event handler
-= : remove this event handler
= : clear event handlers, then add this one
I believe that's the mechanism they're using in C# with delegates (except maybe for the third one).
Re:Good conclusion, poor article (Score:1)
Granted this would be nicer integrated directly into the framework, but you can still do it yourself if necessary.
Re:Good conclusion, poor article (Score:1)
You can't link many events handlers to a single event, but you can link a single handle to many events, if they have the same event type.
When do you need to link an event to many handles? please give an example.
Re:Good conclusion, poor article (Score:2)
True, but that should be thought of as an implementation detail. You code to the CLX, not to Qt. Theoretically Borland could in the future rewrite the CLX on each platform straight to the metal without using Qt, and your programs should still compile. In practice they probably did surface some Qt here and there, maybe data structures taken as parameters of some methods, same as they did with win32 in the VCL.
Re:Good conclusion, poor article (Score:2)
Re:Good conclusion, poor article (Score:1)
> Borland's VCL
I would actually be interested in seeing a good comparison of Qt vs GTK vs VCL. I used to be a VCL programmer (C++Builder and Delphi) so would be interested in seeing how they compare.
Cheers,
sd4l
Re:Good conclusion, poor article (Score:2)
You've got a point, but you can still give the steps required to hook up a buttong to an event handler. Doing that would have actually strengthened the argument considerably, precisely because VS is such a mess.
> I encourage you to write it, that would be interesting.
Hey, it's easier to criticise than to create, so I'll restrict myself to that, thank you very much.
> And I don't see your point with fairness.
I meant that as in Qt towering head and sholders above the MFC in the criteria chosen, finding faults in the MFC was almost like taking candy from kids. I was just thinking about comparing Qt to a similarly OO framework.
Advocacy, we never knew thee. (Score:3, Insightful)
This guy doesn't seem to understand much of what he's talking about.
The most glaring clue is this:
For example, to swap two variables, the author used the non commented following line:
a ^= b ^= a ^= b;
This is a cool hack which does not belong to a professional product.
If you don't recognize this, you probably need to go back to school. It's fast, and it doesn't require a temp variable.
Any time you look at low level libraries, you're going to see things like this. They NEED speed. They NEED low memory impact. These things are going to get called in tight loops with a million iterations. Look at QT's code, and you'll see the same thing.
Also telling is the fact that he has nothing positive to say about MFC. I've run across some VERY talented developers, and while I haven't heard them singing MFC's praises, they do have some nice things to say. Advocacy really needs to show balance. Acknowledging MFC's strong points is important.
When he's talking about an add on library called 'codejack', he mentions that tab views are impossible in MFC, yet codejack provides it. Apparently it is NOT impossible in MFC then. It probably isn't a prebuilt widget for the developer to use (which is unfortunate, I'll admit)
QT is a good library, I have no doubt. But please learn how to find good things in other libraries. It will only make your code better. It will only make your advocacy better.
Re:Advocacy, we never knew thee. (Score:1)
using std::swap;
swap(a, b);
If you want to have a nifty hack, then provide a specialization for swap. And don't bother complaining about function-call overhead. If it's really a one-line hack like above, any half-decent compiler will optimize the call away. And if the compiler doesn't, then there's no point in using it to write optimized code in the first place.
Anyone who can figure out why I used a using-declaration instead of explicitly specifying the namespace (ie: "std::swap(a, b);") gets a cookie.
Re:Advocacy, we never knew thee. (Score:1)
Speaking of being beaten (Score:1)
Oreos or chocolate chip? (Score:2)
You're right on both counts. See this Usenet post [google.com] for a little more detail.
Re:Oreos or chocolate chip? (Score:1)
The more C++ I learn, the more I begin to appreciate more elegant langauges like Python or even Java. I think it's nice to look at code and not having to worry about the countless rules, exceptions, etc, that are in C++.
I wonder how many things like that above I should use my own code. Perhaps I've been doing do much of it, and I should just "dumb down" my code so I can actually get people to help me develop stuff.
Arcane trivia (Score:2)
I understand the lure of mastering reams of arcane trivia. In fields like medicine, this is valuable. But, when you have to do so just to use a man-made programming language because of how often things are not what they appear, it is a stinging indictment of the poor design of the language.
Re:Advocacy, we never knew thee. (Score:2)
That's hardly a sign of a well-balanced comparison. You can completely blast a product and still have a fair review--IF the product really sucks in the criteria chosen, and you can fully document why and how it sucks. Unfortunately this author didn't do that, blasting the MFC on generalities without giving specific code examples, which OTOH he was more than eager to provide for Qt. Within the criteria used--OO design and ease of use--the MFC would pitifully fail against Qt, but you wouldn't know it reading this article.
Re:Advocacy, we never knew thee. (Score:1, Informative)
> It's fast, and it doesn't require a temp variable.
Yeah, great. But I better have them fix their bugs, their crashes and their memory leaks than spare a temp variable. Besides, the code appears in a function that is not optimised at all.
You are focusing on the one the example I gave. Does a 500 lines method looks acceptable to you ? Do you think this is also to spare the cost of function calls that they use so many of them ? Or that having private members declared public is good ?
Their code is crap. It is good in the sense that it makes it a lot easier to build powerful GUI applications and that it works most of the time. But it is crap when you read it.
> Look at QT's code, and you'll see the same thing.
The big difference is that in three years of Qt programming, I had just to look once at Qt's code to be sure I understood the doc properly. With Codejock, there are stuff that are simply not documented, and stuff that you can not use if you do not look at the source code.
> Acknowledging MFC's strong points is important.
I am sorry, I haven't ran into them, except for the fact that it comes free with Visual Studio. But I'll add any if you have one to propose.
I recognised we are not good writers. And we made one mistake in this article. We did not point out that we did in no way pretend to be objective. We were just sharing our experience of Qt programming and MFC programming. I'll add a disclaimer in that direction tonight.
Re:Advocacy, we never knew thee. (Score:2, Insightful)
Re:Advocacy, we never knew thee. (Score:2)
According to Don Box (COM guy, now works at Microsoft) the number is 0 - zero! nil! (He mentioned it in his keynote address at Microsoft Developer Days 2001 in Copenhagen)
Food for thought!
Re:Advocacy, we never knew thee. (Score:2)
Re:Advocacy, we never knew thee. (Score:2)
Don Box (Score:2)
Would that be the same Don Box who wrote about how COM was wonderful for years, but now says it's crap and we should all use .NET?
You should be very careful when listening to two-faced Microsoft weenies, particularly when they're demonstrably wrong. MFC was used in writing Visual Studio itself for a long time (though never, AFAIK, in writing things like Office).
Re:Advocacy, we never knew thee. (Score:3, Informative)
a ^= b ^= a ^= b;
If you don't recognize this, you probably need to go back to school. It's fast, and it doesn't require a temp variable.
Bull.
It's an overly clever hack that doesn't belong in a professional product. Why? Four reasons:
The "comparison" article is poor at best, but in this aspect it is 100% correct. XOR-swapping is a cool hack but has no redeeming values other than its coolness, and cleverness for its own sake has no place in professional code.
Re:Advocacy, we never knew thee. (Score:2)
This code has 2 memory reads and 2 writes, whereas the xor construct assembles to a monstrosity with far more memory access than necessary. So yes, on gcc the normal swap is much faster, but a well-assembled xor construct, with just the 4 required memory accesses, would probably only be a few cycles slower, rather than a few hundred. The memory accesses contribute the great bulk of time consumed.
Re:Advocacy, we never knew thee. (Score:2)
Standard version
Total: 386: 12 cycles, 486: 4 cycles.
XOR version
Total: 386: 20 cycles, 486: 8 cycles
The XOR approach does have the advantage that it requires only one register, but it consumes so many more cycles that it would still be faster to add a pair of mov instructions to save and restore the contents of bx and then use the standard approach. This would bring the total timings of the standard approach up to 18/6.
Now, of course that would certainly be *efficient*....
So, identical performance (on these processors) but one less register. Here, the XOR swap is a win. It would be a win even if it took a few more clock cycles.
Now for the explanation of the "almost": Swapping the contents of two general-purpose registers is completely stupid. Instead, the compiler should "mentally relabel" the two registers and go on about its business. Now, some x86 registers all do have special meanings with respect to some of the higher-level instructions, but swapping values around to prepare for execution of, e.g. a REP instruction is something that the C programmer should never even dream of being concerned about.
I see no realistic situation on any platform I'm familiar with where XOR swapping is a performance win over standard swapping. That's not to say it isn't a win somewhere on some platform, but choosing to write C code that XOR-swaps is a bad idea, because most of the time you won't end up with a better result and you will probably confuse the poor bastard who has to maintain your code later.
Re:Advocacy, we never knew thee. (Score:2)
And, yeah, I know the x86 registers aren't completely general purpose, which is why I mentioned the REP instruction. I do agree that the cool hack is occasionally useful for assembler programmers who need to swap a pair of regs to set up some other instruction but don't want to use another register.
I, myself, was never clever enough to use it that way, so I learned something here, too. Not that I expect to write much assembler these days; compilers are too good and processors, non-embedded processors at least, are too fast and too danged complicated for hand-optimized assembler to be cost-effective anymore... more's the pity, that stuff is fun.
Re:Advocacy, we never knew thee. (Score:1)
Re:Advocacy, we never knew thee. (Score:2)
sh-2.05a$
xorswapping 10 secs: 6999572 iterations
tmpswapping 10 secs: 7785816 iterations
The code for this is here [hackerheaven.org]. I know it's not really a representative benchmark, but it does show the point somewhat. And yes, using a temp variable is hella faster.
MSDN (Score:2)
Re:MSDN (Score:2)
If you compare the API defintions of one API (say ADO) to the API definitions of another (say RegExps) the API documentation is often in COMPLETELY different formats, and we won't even talk about where some of those API docs are located.
The API documentations frequently don't explain what parameters are supposed to (or allowed to) contain, and even if they do their frequently listed on a seperate page without any explanation of the meanings for the various values.
Oh, and good, standardised documentation about those COM/COM+ error codes located in a single and easily accessible location? Forget.
I hate to rant here, but I've been dealing with MSDN's limitations for well over 6 years now and it's hardly better now than it was 6 years ago.
In all honesty, I can find the solution to my problem 10x faster by going straight to groups.google.com. I find information in the MSDN archive quicker from groups.google.com than I ever do searching for it directly.
SUN's Java documentation is an example of how things should be documented. It's not perfect, but it's 1000x better than what MSDN offers.
HTML help is EVIL (Score:2)
Re:MSDN (Score:1)
The index and search are usually good. You very rarely have to browse the contents for stuff.
Grepping the windows API headerfiles is also very useful.
The API documentations frequently don't explain what parameters are supposed to (or allowed to) contain, and even if they do their frequently listed on a seperate page without any explanation of the meanings for the various values.
I've always found them good in that respect - often equal or better than Solaris man pages, say. (IMO, at first glance the QT docs don't look quite as good, but I will give them a better look.)
Oh, and good, standardised documentation about those COM/COM+ error codes located in a single and easily accessible location? Forget.
You can get most of them from winerror.h (with some description). Alternatively, there's always the error lookup util installed with Visual Studio.
Development tools? (Score:4, Insightful)
As others have mentioned, the article is really badly written. I cannot comment on the merits of Qt, since I've done practically nothing with it. But I've done my fair share of MFC, and it's quite ugly - I find it hard to believe that *anything* solving a comparable problem can be much worse.
But my main point is this: When dealing with stuff like MFC you need to factor in the quite helpful development tools that the Visual Studio suite consists of. I have yet to see something of that quality from anyone else (except possibly Borland), and so far I've found only KDevelop to be reasonably useful. The MFC library (I flatly refuse to call it an object model) is ugly, but to some extent this is ameliorated by the IDE. I *know* this is not the way it should be done, but it's there and it DOES help...
MFC (Score:2)
Fortunatly I wrote my own Windows wrapper before MFC came along.
MFC might look good in comparison to Visuial Studio which must be one of the worst Dev environments I've ever used, I'd never take a job where Visuial studio was a requirement.
Re:MFC (Score:1)
There's a learning curve, agreed, but ATL is very powerful if you want a COM implementation that covers all corner-cases and configuration properly. The ATL with VS7 has been beefed up with MFC-style helper classes (CATLStringW, etc.) and is an absolute dream to use. Honest.
MFC might look good in comparison to Visuial Studio which must be one of the worst Dev environments I've ever used
What's wrong with it? IMO, it's a nice editor with a well-integrated (and useful!) source debugger.
Visuial studio (Score:2)
Here's my top hates....to the point of frastration.
1: (this is trully evil) the MDI interface.
2: Dialogues have loads of tabs but arn't resizeable.
3: Options arn't natural, e.g. right click on a project and I get
4: (part of 3) Options are hidden all over the place.
5: MSDN HTML help is shit (not the use of HTML for help, but the way MS have used it)
Here's a few things in CBuilder Delphi (as an example) that are farrrr superior.
1: No evil MDI
2: Options are quite easy to find
3: Fully RAD
4: Code compleation is highly typed e.g.
int a =
only lists things that can return or be cast to an int.
5: The help is generally quite good.
6: The api for extending CBuilder/Delphi is great and easy to use (easier than Visual Studio).
Qt vs .NET? (Score:2, Insightful)
Re:Qt vs .NET? (Score:1)
Re:Qt vs .NET? (Score:1)
I guess if a SW team has lots of experience in MFC and likes it, they might use it for new projects, but I think most Windows developers would prefer to use
Re:Qt vs .NET? (Score:2)
That's an interesting perspective. Personally, I don't think there are many Windows programmers using .NET for new development.
Re:Qt vs .NET? (Score:1)
Well, I can't prove that there are, but there were about 5000 programmers who traveled to Orlando back in July of 2000 to learn about
I can't imagine why anyone writing a new Windows only application would not at least consider
Re:Qt vs .NET? (Score:2)
Sorry, I couldn't resist the cynical one-liner. In all seriousness, though, I think .NET is much hyped but, so far at least, little used. There are always those who will go with whatever Microsoft produces. They went for Visual Basic first, they went for COM first, and they'll got for .NET and C# first. The remainder of the Windows programming world -- the vast majority -- is more interested in making a product and getting paid for it, and will therefore probably stick with tried and tested solutions like VB6, VC++6 w/ MFC, and so on for a long time to come.
Microsoft is trying the same trick with the programming world that it's attempted with Windows and Office users recently: produce a new version, with limited new features applicable to a few users only, and hope the bigger version number and hype is enough to get everyone else moving as well. It hasn't worked well so far with office users, and I doubt the programming world (for all their natural instincts to use the latest and greatest) will be any more easily fooled.
To give credit where it is due, .NET does seem to offer genuine advantages for those writing certain types of application, notably anyone interested in web services. (I don't know why anyone would write for it in "Managed C++", though; if you're doing new development for .NET, you might as well use C# or VB.NET so you can take advantage of it cleanly.) For the average desktop application, though, .NET seems to offer little other than a whole new class library to learn and a whole new massive overhead to install.
You're right that anyone programming for Windows should probably consider it in their own circumstances, of course. I spent quite some time looking into it during the months running up to its release, from the point of view of writing a typical desktop Windows application. I found no compelling reason to move to the new technology, with all the retraining and redevelopment of libraries and tools that necessarily requires.
Re:Qt vs .NET? (Score:2)
MFC vs wxWindows discussion more interesting (Score:1)
QT vs MFC (Score:1)
As a previous poster mentioned the VCL is really nice too, its just a shame that I have to use Object Pascal to use it I hear a C++ version is coming to Linux though.
As for MFC I don't really like it, it just doesn't feel object orientated enough!
Kylix 3 just released with c++ and OP (Score:2)
Don't know why this hasn't made it to
Re:Kylix 3 just released with c++ and OP (Score:1)
Too dismissive of Object Pascal (Score:1)
So you'd rather have a 'grown-up' but non-OO and kinda ugly language than one with a flexible and powerful object model, RTTI [acronymfinder.com], inheritable message-handling framework, copy-on-write strings, etc., etc.?
All the current hype over .NET is old hat: Delphi has had most of what .NET has to offer for years (not surprising given who wrote them both [inner-smile.com] ).
Object Pascal makes me much more productive than C++ ever did, and I'm not talking about GUI gubbins here, but the 'invisible' back-end stuff.
MFC not *that* bad (Score:2)
However, MFC isn't that bad. If you're developing a Windows application in C++, and you're forced into using MS only technology cause your boss won't pay the $1000+ per developer license for QT, and your choices are between using MFC and the base Win32 API, then MFC is the way to go. Granted, the Document / View Architecture is uh... well it's *odd*, but once you get the hang of it you can whip out a reasonably good GUI quickly.
MFC does do some nice things for you, mainly serialization and treating controls as objects, and the Message Maps are a vast improvement over the 10 page switch statements for Message Handling in Win32..
However, since MFC is "dead", I'd rather see a comparision between C# and Windows Forms vs. C++ and QT.. (and a lot of this I posted on Microsoft's own news groups.. hehehehe)
Seriously, If you want to see something that's godawful, look at C# and Windows Forms.
The below is from a post I submitted to Microsoft's own news groups.. to date, I have not gotten any kind of response from Microsoft. A couple of "Wait for Borland C++ Builder.NET" responses.. but nothing from Microsoft. Since MFC is "dead" and .NET is the "way" for Microsoft now, it makes sense to post this..
Especially if you have an option between QT and .NET... PICK QT FOR THE LOVE OF GOD.
While trying to develop a dockable tool window (much like the ones found in Visual Studio.NET) I've done a lot of research and had a lot of grief. Out of the box, you can't create a dockable window.
No one seems to know of any royalty free, open source solutions, and the .NET Magic library doesn't count. Look closely at the source and
you'll find that there's an awful lot of Win32 API calls being made
via PInvoke, which, per Petzold on page 237 of "Programming Windows
with C#", is "no longer writing managed code, and certainly not
platform-independent code."
So for the .NET Magic library users, what's the point of even
bothering to use C# and Winforms if all you're using it for is to wrap
Win32 API calls? Why not just use C++ compiled as a Win32 app and get
the performance increase and greater toolset? I know that making it a
dockable window is just a window style, (FWS_something, too lazy to
look it up right now, which you would think would just be a property
of a Control type, since Control seems to Map 1 to 1 to a Window.)
Which brings me to the largest gripe I have about the .NET framework:
The Winforms really suck. The overly simple UI controls it exposes are
simply not acceptable in today's enviroment. First, I'll give
Microsoft credit: Visual Studio.NET's UI is absolutely stunning, and
the C# language has some nice features....
However, it is seemingly impossible to create any form of advanced UI unless you derive your own controls or use PInvoke to create GenericPane window classes. And according to Spy++, those nice dockable, resizable windows are of Window Class GenericPane. Seriously, take Docking toolbars for example - we've been able to do this in MFC for years, so using "pure" C# really seems like two steps back instead of the leap forward the PR machine would have you believe. For any kind of advanced UI are we really forced to pony up money for third party libraries or roll our own? (And again, for the goal of "pure" C#, using PInvoke doesn't count.)
What's really maddening is that there's so many other language / RAD toolkits that do this much better. C++ / MFC, C++ / QT (for cross platform), Java / Swing, to name a few.
Even the Menus aren't dockable / moveable. What's the point of using managed code if the only applications you can quickly produce look like crap?
Re:MFC not *that* bad (Score:1)
Great, if this was 2-8 years ago... (Score:2)
Tired: MFC
Wired: System.Windows.Forms
Anyone creating an app from scratch right now, or porting an app not written in MFC, should _not_ be even considering MFC. New MFC enhancements are usefull for maintaing the (large) base of MFC apps written in it over the last ?10? years. It's time is over though.
New != better (Score:2)
I assume from the rest of your post that you're advocating using .NET instead? Why on earth would any development team of sound mind do that?
MFC, OTOH, while kludgy and less than well-designed, has a developer base of zillions across the world who know how to work around its kludginess and get the job done. It is tried and tested, so at least you have a pretty good idea where the bugs are. There is a lot of truth to the old saying "Better the devil you know".
If I had a new development team starting on a Windoze app, MFC certainly wouldn't be my first choice of tool -- far from it -- but it would be waaaaay ahead of anything to do with .NET.
MFC is NOT replaced by Windows Form (Score:3, Informative)
It has been three years since the last major update to MFC and ATL. With all the press on Microsoft®
There's a new MFC DLL (MFC70.DLL) that is no longer backward binary-compatible with MFC42.DLL, but your source is still compatible (although message maps have been made more type-safe, so that may break some code).
MFC and ATL are much better integrated, and common classes such as CString are now shared between the two libraries.
Header files are synchronized with the latest Platform SDK, supporting UI features in Windows 2000 and Windows XP such as themes and manifest resources, Active Accessibility®, and new common dialog boxes.
Many new UI classes have been added, including support for using DHTML in dialog boxes and enhanced bitmap support with CImage.
New utility classes can be used in both MFC and ATL applications, such as regular expressions, performance counters support, and security.
Now there's support for consuming Web Services in MFC applications and writing Web Services and applications with ATL Server classes.
High-performance access to databases has never been easier using the new OLE DB attributes and classes.
STL has been updated.
A bit *too* nice about Qt (Score:3, Insightful)
I can't help feeling that, whatever its position on MFC, the article was unjust in its uniform praise of Qt. Some of the container classes there (QMap?) appear to be somewhat inferior versions of the STL equivalents, in case the C++ library in use doesn't support the STL parts properly, but doesn't support all the template guff required to use them(?!) To their credit, they do at least try to support the standard interfaces so you can use their containers with standard algorithms, which is a definite improvement over MFC.
The article also seems to praise QString, which is yet another string class with a Big Bloated Interface(TM) (doh!) that thinks using only mutable strings is the way forward (double-doh!) and reference counting/copy-on-write of a mutable string is a Good Thing (double-plus-doh!). These are well-known design flaws with both approaches, relating to efficiency, thread safety, etc. If they wanted an improvement, they should have provided an immutable string class with a suitable set of operations, and a string-building framework to go with it where it's genuinely the appropriate tool. Oh, and being in native Unicode isn't particularly clever. Why not just use std::wstring, anyway?
As for the graphics, sometimes I want to lay out my dialog controls in exactly the positions I decide to put them in. Dynamic generation can be a good thing, but don't mandate it, because sometimes it's simply wrong.
I also have quite a bit of experience of i18n, and I'm all-too-familiar with the pain of translations, etc. For those who don't know, l10n (the opposite to i18n, i.e., making your location-generic application work in a specific locale) is about 10% translation and 90% integration, fixing up all the dialogs, ensuring that your UI can cope with reordered sentences (hope you don't like the IOStreams approach; printf had it right years ago) and so forth. A simple tr() function is not the silver bullet here, contrary to what the article seems to suggest.
Don't get me wrong, I think Qt is a nice library, and much better than many of the alternatives. But some of the claims in the article are just downright false.
Re:A bit *too* nice about Qt (Score:1, Interesting)
In 3 years of development with Qt, I haven't met any of the problems you describe. Maybe I am not writing the right programs.
> If they wanted an improvement, they should have provided an immutable string class with a suitable set of operations,
You mean a QConstString [trolltech.com]
> Oh, and being in native Unicode isn't particularly clever.
This is a comparison with MFC. You are telling me that their choice is really stupid and I agree. In comparison, the other choice looks clever.
> As for the graphics, sometimes I want to lay out my dialog controls in exactly the positions
You can do it if you want, even with Qt Designer. But I don't see when you want to do that. Could you give an example ?
Anyway, in the big majority of case, you want things to layout automatically and it is easy to do that with Qt.
> ensuring that your UI can cope with reordered sentences
QString can deal with reordered arguments.
> A simple tr() function is not the silver bullet here, contrary to what the article seems to suggest.
Yes it is. gettext() had it right from years. This approach allow the developer not to worry too much about translation, allow the translator not to cope with compiling stuff and get automatic update, and allow the user to add new language without hassle and to switch easily from one language to another.
Qt uses exactly the gettext() approach, with their own tools.
Re:A bit *too* nice about Qt (Score:3, Informative)
Maybe you've been lucky. Who knows? The fact remains that there are demonstrated problems that can occur when using COW strings in a multithreaded C++ system, and further, the advantages of using such a design are mostly illusory anyway. It seemed like a good idea at the time, but on reflection, it turned out not to be. (BTW, I have watched an application fall over for no good reason because its string library wasn't multithread-safe when it should have been, and I've watched the development team waste several man-days of time trying to find the bug in their code -- which wasn't.)
I don't think so. I mean a full-fledged immutable string class that supports the usual look-up and combination operations without the mutating ones, and a clean interface to convert between such a class and a vanilla QString. AFAICS, that's a whole world away from QConstString.
In simple cases, I agree, an automatic layout can be very helpful. OTOH, on a program I used to work on, extensive used was made of tabbed dialogs. The layouts of most of them were fixed across all of the tabs, so that similar controls didn't jump around irritatingly as you flipped from tab to tab. I don't know if Qt's automatic layout system would handle that, but certainly no other one I've ever seen does. Automatic layout is simply not the best answer to everything, which the article seemed to be suggesting.
With all due respect, if you think a simple translation mechanism like that is all there is to i18n/l10n, I can't believe you've ever worked on a large-scale multi-lingual application. There are other locale-related formatting issues (date/time, currency, etc). There are languages where routine system calls don't work on some strings (try a toupper on the German word Strasse, and then try the same on the same word written with a Schaffes s, and then compare them for equality). In Japan, most machines speak MBCS, not Unicode, so you need an effective means of converting between them, preferably as soon as the MBCS enters your program and just before it leaves so you can at least use Unicode internally. Some languages read right-to-left, or top-to-bottom, or even more devious variations, and you have to adapt your UI to cope with this, particularly when laying out dialog boxes and such. It is not as simple as a tr() function. (I'm not saying Qt couldn't cope with many of these issues, just that the emphasis placed on the tr() function by the article is overstated.)
Re:A bit *too* nice about Qt (Score:2)
A major problem with gettext() is that there can only be one translation of each of the strings in the original language. What happens when you use an English word with different meanings in different contexts, that should be translated to separate words in another languages? Usually your messages will be long enough that this doesn't happen, but in a GUI you may well use text labels with only one word in them.
Re:A bit *too* nice about Qt (Score:1)
Qt is pre-STL. Also, it makes different design tradeoffs. The containers are pointer-based, and are implement using the "inheritance from void*" container idiom which means that the "template bloat" is minimised in these classes. It makes sense in Qt, since Qt programs use pointers and not values.
These are well-known design flaws with both approaches, relating to efficiency, thread safety, etc.
They weren't well-known at the time Qt was written. gcc still ships with a reference counted std::String today.
Why not use std::wstring
It wasn't an option when Qt was written. You're writing this as though Trolltech had full benefits of the ANSI/ISO 1998 standard at the time they implemented it. Qt was written in 1996.
Re:A bit *too* nice about Qt (Score:2)
Sorry, didn't mean to come across as bashing Qt. I realise it was first created pre-standard and couldn't have benefitted from the experience gained by the C++ community over the past five or so years. I was trying to highlight flaws in the evangelism of the original article by citing obvious concrete examples of false claims (containers better than STL, yada yada).
Re:A bit *too* nice about Qt (Score:1)
I agree with the overall impression. The article comes across as cheerleading, and not a balanced comparison. I haven't used MFC, but I find it hard to believe that it's as bad as they make it sound. The containers are adequate, but the design is not as clean as STL, and there are some benign warts like "current" nodes in lists, and index based access in lists (I say bening, because one can just ignore these misfeatures).
Re:A bit *too* nice about Qt (Score:2)
Can you explain these inefficiencies, or provide a URL to some analysis about them? Personally, I think the copy-on-write stuff is really cool. Not just QString, but even container classes like QValueList won't duplicate your objects unless needed. Native Unicode makes things simpler too...
Problems with string classes (Score:2)
The best exposition I've seen was a set of three articles on "Reference Counting" in Herb Sutter's Guru of the Week [www.gotw.ca] series. You can find articles 43-45 on his web site, and as he notes there, an updated version is available in one of his books. You could also search the history for the Usenet group comp.lang.c++.moderated, where GotW is posted, to see more discussion on the subject. You might also want to check out the most recent GotW (questions but no solutions on the web site, but check the newsgroup history) for a few thoughts on why string classes tend to have overbloated interfaces.
Addressing some MFC points in article (Score:1)
The Microsoft Foundation Class (MFC) is a graphical toolkit for the windows operating system. It is a more or less object oriented wrapper of the win32 API, which causes the API to be sometimes C, sometimes C++, and usually an awful mix.
The only non-C++ you could complain about in MFC is the use of some Win32 API structures without containing classes/accessors. Under the circumstances (given the number of them!) I don't think this is too big a deal.
MFC programming requires the use of Document/View model and templates.
No, it doesn't. If you don't want Doc/View, you can just use the MFC-dialog-application template.
I've never seen the other problems you mention:
I'd consider this a plus - lean (or as lean C++ as you'll get), efficient (ditto) and feature-complete.
And there are nasty tricks, without any consistency. For example, if you create a graphical object, it is not created until the Create() methods has been called. For dialogs, you must wait for OnInitDialog, for views, you wait for OnInitialUpdate,
No. This *is* consistent and logical. And OO.
MFC is full of these nasty tricks. And it is hard to debug.
'nasty tricks' is a little extreme. MFC integrates very well with Visual Studio's debugger and is relatively simple to debug. You're provided with the source code to step through if you need it. I've never had any trouble.
Qt is based upon a powerful callback mechanism based on signal emission and reception inside slots.
This sounds exactly like the Windows message model that you've just slammed (!). I don't see any problems with the windows message model - but then I'm familiar with the API.
The interface creation section: DDX and IMPLEMENT_DYNCREATE (why do you need that for your UI?) are relatively easy to understand - maybe try Prosise's book if you need enlightenment. You don't need to touch the message loop - it's buried in the MFC DLL and covers all cases. You can quite happily manufacture dialogs at run-time by calling Create() on control objects in the OnInitDialog() method.
Qt designer lets you do things that are not possible in MFC, like creating a listview with pre-filled fields, or using a tab control with different views on each tab.
Pre-filling a list view should be done in OnInitDialog(); the interface is quite simple.
Tabs are a different matter; you need to create child dialogs for each separate pane. This closely reflects what's going on in the OS API. It's not too difficult and there are good sample applications. Alternatively, there's a very simple interface to create complex property pages already provided.
Visual's documentation, MSDN (for which you must pay separately) is huge, on 10 CDROM.
It's no more than 3 CDs. It's bundled with Visual Studio. It's available online at http://msdn.microsoft.com/library/ [microsoft.com]. And it's very good, complete documentation.
MFC's unicode is very easy. If you need to change the entry point of your application then you're doing it wrong; you probably need to change
If you're given non-unicode third party library then the third party ought to be able to supply a unicode version by changing a few flags and rebuilding. I'd be surprised if many vendors couldn't supply Unicode libraries if you asked them.
Resources and string-tables are part of the Win32 API. I find them useful and easy to program for. You have to try quite hard to load resources from the wrong DLL; all resources are indexed on exe/dll module handle as well as resource ID.
Latest MFC DLL: you should always ship the one you develop and test against! Win2K+ allows you to install a copy of the DLL local for your application. Alteratively, there are simple-ish mechanisms to auto-download the latest MFC from Microsoft.
To address some of your list of QT advantages,
QT and moc (Score:2)
Re:Why would you use Qt? (Score:2)
And not portable. Remember, it is becoming more practical to take off the blinders and support other operating systems. Writing a new application to support both UNIX and Windows, for example, not only results in a better application architecture (abstracted for portability) but also distributes risk (so what if either Microsoft or Apple or Linux falls by the wayside; I'm covered).
So, to fight a troll with a troll:
Why use MFC...when Qt provides better risk mitigation and has been industry proven.
Re:Why would you use Qt? (Score:1)
You could always recompile with the help of MainWin [mainsoft.com], but the performance is horrible. This is essentially what Microsoft uses to port IE to UNIX. That's why wxWindows and Qt are very appealing to me right now.
Re:Why would you use Qt? (Score:1)
Re:Why would you use Qt? (Score:1)
I think your second point is valid, but your first, not always. If portability is not a requirement, the architecture is not improved by the introduction of an abstraction that doesn't model the problem. In addition, comprehensive compatibility would require that the application be portable to other operating systems in addition to those based on Windows or Unix.
Re:Why would you use Qt? (Score:1)
Qt doesn't use abstraction in the same sense of (for example) AWT. It implements its own widgets for each target "look and feel". The down-side is that you possibly end up with something that looks slightly different from the target platform (no emulation is perfect), but you don't suffer the same performance impact or awkwardness (for example, the logical intersection of all targets problem)
Re:Why would you use Qt? (Score:1)
Re:wrappers (Score:1, Informative)
CodeJock integrates with MFC, so it can not get rid of many of MFC pitfall. And it is not a very well engineered product.
> you go from EnableWindow(window, verb) to window->Enable(verb)
If it was just that, that would not be a problem. Unfortunately, many MFC calls are usually more complicated, with obsolete arguments and strange naming.
You know when using it that the product is old and that they have tried to improve it over the time. Now, they have dumped it for
Re:Notes from a 6-month MFC coder (Score:1)
with
that has all these weird constants and macros in them with names like '__AFX_DEFINED_DDLXCI_AXWEC_UBER_MACRO_EXCHANGE_D
They're the header include guards - which are sensibly long (they contain a GUID) and easily recognizable.
And you can just pull values out of a dialog box; you have to use this thing called "Direct Data Exchange" that I never really figured out,
Yes you can; you can call 'GetWindowText()' on any control. If you didn't associate a control variable with your dialog then you can call a method on the CDialog object to get an MFC you can call these methods on.
DDX is just a convenience:
and you have all these magic cookies that get defined in some header file somewhere
The Win32 API is constant-heavy. You can't completely escape it and MFC does well to not try.
and you don't even get to write main()
You use InitInstance() in your CWinApp derived object if you need a main() alike. Alternatively, just write UI response code.
all the classes start with the letter 'C' and everything is in hungarian notation
Such is the Microsoft coding convention.
WHERE DO I DRAW STUFF IN MY WINDOW?!
Override OnPaint() in your view object if you really need to - this exactly corresponds to WM_PAINT in non-MFC apps.
Re:Notes from a 6-month MFC coder (Score:1)
Anyway, I still love Java.