Link to home
Start Free TrialLog in
Avatar of pete_bristol
pete_bristol

asked on

Advice/Oppinion please - MFC

Dear Experts,

I guess there is no correct answer to this question but i would appreciate some varied views so that i may decide the best way forward.

I have been learning Console c++ for a while now and have decided it is time to move up to Windows programming but i cannot make my mind up as to whether i should concentrate on API or MFC.

Programming is currently only a hobby but i often "dream" of being able to take it up as a job so some kind of advantage here would be good.

I've written a couple of simple (*very*) Win Programs but they really end up looking like C programs - is this so wrong?

It seems that using MFC will force me to use c++ more as it was intended i.e classes and stuff, but i guess the future of MFC is ultimately limited(?) whereas the API stuff will be around forever(?)

Furthermore, would knowledge of MFC develope any skills that would enable me to gain a better understanding of programming games in Direct X?

Finally, a really impossible question, how long effectively do you think that C++ will be around as a main stream language? I just wonder whether by the time i get profficient at it, it will be obsolete!!

All help, advice gratefully received.

Many thanks

Pete
Avatar of Sys_Prog
Sys_Prog
Flag of India image

Regarding
MFC Vs Win32 API
I would prefer doing Win32 initially (may be thru Charles Petzold book) and then go on to do MFC
This is because MFC is a wrapper around Win32 API's
Also, MFC is quite cumbersome and requires heavy knowledge of C++ virtual functions concept, macros and other stuff
So, if u are very comfortable with C++ and Win32 Programming, it would be lot easier to program/learn MFC

Learning MFC without Win32 SDK Programming would not give u a detailed idea


I am sure that "C++" would not vanish for atleast a decade or more (that's my opinion)

Amit
ASKER CERTIFIED SOLUTION
Avatar of AlexFM
AlexFM

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Salte
That is a strange misconception:  MFC does NOT force a document/view architecture.  App wizard will build it in if you want it, but it is not at all necessary.  It is a common app layout and if you need that layout, it is very complicated to build it all from scratch.

I also disagree on another point.  Hungarian notation -- in which the programmer describes the variable data type in the variable name -- is an EXTREMELY useful convention.  If you open a thread I'll be glad to debate you on the issue :)

-- Dan
>>Another gripe I have with MFC is its use of hungarian notation which is "evil" and should never be used - by "evil" here I mean that it is something you should avoid at all cost. Hungarian notation is bad period. If
>>you want to know why I can enlist the reasons for you in another posting.

You're the first person I've heard complain about the hungarian notation.  What do you think is wrong with it.

IMHO, it's a good standard, and it's better then nothing at all.  There is no other widely used naming standard that I'm aware of, and I would recommend all newbies use it.

Also you have more choices then just the Doc/View for using MFC.  If you're program doesn't fit Doc/View paradigm, then you can use a Dialog application.
If you're program runs in the background, then you can just create a Console application with MFC support.
You can use MFC in many ways, and in many types of applications.  So I don't see that been an issue.

I would recommend programming in MFC, mainly because of the amount of information available on the web.
There's a lot more source of information for MFC then there is for .Net and Win32 programming combined.

More work places still use MFC then .Net, and many are relunctant to crossover.

I don't see MFC kicking the bucket any time soon.
I agree with AlexFM, in that MFC's containers are ugly.
I recommend you use the STL containers over MFC containers, with the exception of the CString class.

The CString class is my favorite class in MFC, and I really which the STL library had something similar other then the std::string class.
The CString class has a great interface, and you'll find that it's has a better optimization then the std::string class that comes with VC++ 6.0.

If you decide to learn MFC, I highly recommend that you learn this class really good.  I don't know how much time I wasted on code that I later found out CString could do in one line of code.

I would also recommend that you do mix some STL with your MFC code.  That way when you do have to go to a non-MFC environment, your skill set will still be good.
Here is one aspect that was not covered yet: Even though you may only use MFC, you will eventually learn quite a bit about API programming, but by doing this via MFC, you avoid the confusion about what belongs together: The object concept in MFC presents all methods that are about a certain object (e.g. a dialog) as part of the dialog class. Most of these methods have their counterparts in API, but you don't get this grouping, so it's much harder to memorize what functions go with which object. Also, if you are looking for a method, but forgot it's name, you can just browse through all class members, until you find the one you are looking for. With API this is almost impossible.

Once you are familiar with one OO GUI framework, it's easier to move on to a different one (this can either be another Windows framework like .NET, but also GUI programming on a Mac or Unix).

... and Re: Hungarian notation: You don't have to use it, even if you program with MFC. I had ten years of Unix programming experience before I started with MFC. I never got used to the Hungarian notation, so I don't use it.
Avatar of Salte
Salte

Axter said:

You're the first person I've heard complain about the hungarian notation.  What do you think is wrong with it.

IMHO, it's a good standard, and it's better then nothing at all.  There is no other widely used naming standard that I'm aware of, and I would recommend all newbies use it.

I say:

Ok, let's try a semi-real life example. You are writing a program and you declare a variable in it. It is a local variable in a function:

void func()
{
     int iNumber = 5;

     iNumber += some_func();

     while (iNumber < 7)
         do_something(iNumber);
}

Appear innnocent, doesn't it?

Well, firt off. what does the 'i' tell you in front of iNumber? Well, it is an int. But then you can easily see that from its declaration so it is reduntant. Now, reduntant information isn't bad you may think but there are some issues here:

1. A declaration of a local variable should always be close to its use in a function. If there is a long distance between declaration and reference your function is most likely too big and instead of using hungarian notation you should rather consider making your function smaller.

2. Worse, later on in development you may find that int doesn't cut it, you have to change the variable to a double. Having a double named iNumber is a lie, you say it is an int but it really is a double. So instead of information you have MIS-information which is worse than no information.You could change the name to dNumber or some such but then if you place a burden on yourself to not only change the type but also change the variable every place it is found - and don't change other variables which happen to have the same name and which aren't changed.

So you have something which is reduntant and doesn't give much information to start with running the risk that it gives the wrong information as a program grows and changes. Get rid of it.

There are other issues with the hungarian notation as well but that it is useless and risking providing false information should be good enough reasons to stay away from it. That the names tends to be unpronouncable is also a good reason not to use it.

In particular in the windows setting it is particularly bad. Windows do for historical reasons use the prefix 'lp' to mean 'long pointer' or 'far pointer'. This was an issue in old 16 bit programs where you had near pointers and far pointers and you always had to know which one you were dealing with at this moment. In 32 bit programming where a pointer is a pointer and there are no near and far pointers a more suitable prefix would be simply 'p'. Again, the world has grown away from the traditional hungarian notation which is kept for backwards compatibility but which makes absolutely no sense in a 32 bit world.

The only form of prefix to names which are good are:

1. prefixes to external library functions (you only export functions, never variables, right?)

2. Prefix M_ or m_ to mark a class member as a non-static member of a class. A class member is typically declared in a headerfile and used in a .cpp file so it is a good idea to mark such variables so a reader of your program pay attention. Of these two I have come to more and more prefer M_ and abandon m_. The uppercase really sticks out in a mostly lowercase program code and that is a good thing. It shoud be used for all data members and can also be used for private or protected member functions.

3. Prefix S_ or s_ to mark a class member as a static member of a class. It can also be used for private or protected static member functions. As for the M_ case I prefer S_ over s_.

As a possible extra candidate are E_ or e_ for enum defines although I am not convinced that that is a good idea.

Specifically local variables should simply be given reasonable names without any specific prefix. The declaration should be very close to the reference anyway so giving a reasonable name without any artificial prefixes is a good idea.

Global variables shouldn't exist at all, put them in a reasonable class or namespace and refer to them using that class or namespace (no 'using namespace ' for these references thank you).

Thus:

namespace A {
   int counter;
};


void func()
{
    ++A::counter;
   ....other code here...
}

Here the explicite namespace A indicates which module it is and where it is declared, so no prefix is necessary.

In short, we don't need hungarian notation it is an abomination.

Alf
About the doc/view etc.

I am aware that you can make console programs using MFC (but why would you?) or a dialogue application etc.. Yet, it is still articficial. The MFC was from the ground up created to support and implement a document/view centric application framework and then they later found that this dialog style also happen to support applications with only view and no document etc etc. However, be aware that creating your application as a dialog application indicates that the windows will look different. You have to do lots of non-obvious tweaking to make it look like a regular document/view application without a document.

Also, I didn't mention about the horrible container classes in MFC. Yes, they alone are good enough reason to stay away from MFC. I know you can mix and use STL classes together with MFC but if you are making a windowing application I would far recommend that you look into C# and .NET rather than tweaking with MFC.

Alf
I like prefixes. When I am typing and want to use some string variable from the class, I type m_s and press Ctrl+Space, and all string class members are shown in the context menu. In my .NET programs I don't use Hungarian notation (according to Microsoft guidelines), and this is not convenient.
I did a lot of programs in MFC, but I never use Doc/View architectute in SDI projects (document classes remain unused in my programs). I also don't use serialization, MFC Sockets, containers and COM.
Btw, for those of you who find hungarian notation so very useful...

what prefix do you give the local variables a and b below?

template <class T>
inline const T & max(const T & a, const T & b)
{
         if (b > a)
                 return b;
         else
                 return a;
}

If they were int you might say ia and ib but then their types are template arguments so they can be any type.

Again, a good reason why hungarian notation is useless.

Alf
looks to me that you have a class with a zillion class members if you want a context menu showing only the string class members etc in order to have a reasonable size.

Some times you have to use a big class but more often than not you can group things  and so you end up with a class with fewer members and therefore also more managable.

In either case I don't consider that as an argument in favor of hungarian notation. As  I said, the main problem with hungarian notation is what happens when a variable changes type and thus create a conflict between the type suggested by the hungarian notation and the actual type declared for the variable. Whatever you find convenient in context menu is a minor issue compared to that pitfall.

Also, what do you do with portable code where a variable is of one type - say int - for one platform but a completely different type for other platforms?

Another problem with hungarian notation is that it really only works for a few selected predetermined types. A C++ program should declare a lot of user defined types and what prefix should you give to them? Should they all have the anonymous 'struct' or 'udt' prefix? Then most of your variables end up having such an anonymous prefix which doesn't really say anything at all. Utterly and completely useless.

No, put hungarian notation where it belongs - in the trash together with other ideas which at first seemed good but which later turns out to be just plain bad after you have given them some thought :-)

Alf
It's clear that you don't like hungarian notation but you have only weak arguments:

1. redundancy

Using hungarian notation you are be able to determine the interface of any function call. Do you really favour a call like

       A::myFunc(name, id, salary, height, desc);

to that?

       CMyClassA::myFunc(strName, id, dSalaray, fHeight, pszDescription);

2. Short functions

It's good to have small functions, but the world is cruel and not all code is made by people which make the efforts to write small functions. So, if you have to deal with software you haven't written yourself, a stringent type notation is a mercy.

3. Changing types

Changing types doesn't occur very often and of course you have to change the variable name if it is serious programming.

4. unpronouncable

Readability is more important than pronouncability.

5. Windows types

I made C++ projects on a Win3.11 platform. And i am very grateful that MS used this kind of notation. And it's good that MS hadn't changed it as some of these projects have been converted to Win32 projects and i still have to support them. if MS changes notation for .NET it's ok but it's an absolute must that the notation for SDK and MFC hasn't altered.

6. it really only works for a few selected predetermined types

That must not be true. In most projects i made there had been rules for private types as well. The pointer, member and static notation applies to all types. For private types you may use suffixes, e. g.  Person* pFirstPerson or Object anyObj. However, most benefits you get by prefixing or suffixing all standard types, especially pointers, e. g.  map<string, Person> personByNameMap, string strDescription, vector<int> intArr, const char * pcszName, char** pszArgs, ... If you would have done that consequently in most of your projects as i did, you wouldn't argue that it isn't useful.

Regards, Alex

Didn't really intend to create a big controversy on this posting where Pete probably get a lot more than he bargained for from this debate.

I will therefore respond to your comments and then let the issue lie. It is not my intention to respond to any more postings regarding this issue on this thread. We might open antther thread but this forum is for people seeking help not for people fighting "religious wars" over what is good/not good style in programming.

>> It's clear that you don't like hungarian notation but you have only weak arguments:

That they are weak is your opinion and not a statement of fact.

>> 1. redundancy

>>Using hungarian notation you are be able to determine the interface of any
>> function call. Do you really favour a call like

>>       A::myFunc(name, id, salary, height, desc);

>> to that?

>>       CMyClassA::myFunc(strName, id, dSalaray, fHeight, pszDescription);

Well, given that the class name is a little better than just the anonymous "A" which would never occur in a real life program I and ditto for the function name as opposed to myFunc I would say "yes".

a) I would assume that name, id, salary, height and desc are all variables declared close to the call so you can see quickly what types they are anyway. Further the strName thing indicate it is a string, if you later changed to enums or some such you would have to change the names of the variables - more work and likely to get it wrong some place.

b) The first form is just as clear as the second given you have the declarations of name, id, salary etc close to the call. It is also more concise and therefore better.

>> 2. Short functions

>> It's good to have small functions, but the world is cruel and not all code is made by people which make the efforts to write small functions. So, if you have to deal with software you haven't written yourself, a stringent type notation is a mercy.

I hear you. I am currently working on a program which was originally designed by other people and I curse every time I see something that is very bad or gives me uneccesary headaches :-) However, I don't think hungarian notation would have helped in any way it might have made the situation worse. Yes, if a function is big and there is a long distance between declaration and use of the local variable you might even be forced to break the function down into smaller functions instead of making use of the hungarian notation. Personally, I would consider that an improvement.

>> 3. Changing types

>> Changing types doesn't occur very often and of course you have to change the variable name if it is serious programming.

It occur more often than you appear to be aware of. Things change, suddenly that 16 bit integer wasn''t big enough so you have to switch to 32 bit or you port the program to another platform which uses a different type for the given item. What used to be a void pointer to some OS resource in one system is an int descriptor in another etc. Now you even have two types for the same variable for the two environments at the same time! Which prefix should you choose? iFoo for the int type descriptor in OS X or pFoo for the pointer to resource in OS Y? Of course, the logical solution is to accept that this really is a type "id of OS resource" and is neither int nor a simple pointer and so you might make up some new hungarian notation prefix for this. There will be many different prefixes when you are done and it doesn't always lend itself nicely to your self imposed straightjacket. What if OS X has two different types for resource A and resource B while OS Y uses the same type for both and they are interchangable in various functions calls?

The worst problem with hungarian notation is something I haven't even touched into yet. You are really mixing things which logically should be kept far apart. The type of a variable and the name of the variable are two separate attributes of the variable. Encoding the type into the name is really mixing the issue and creating problems for yourself. True enough, you can often find various solutions - after all MS used hungarian notation for many years before they found out that it was a bad idea and through all those years they did manage. However, the solutions are a little like "first I break my legs and put myself in a crippled situation and then I get a wheelchair so I can solve the problem of moving around with my legs broken". Yes, you can get around even with hungarian notation but why introduce it in the first place?

>> 4. unpronouncable

>> Readability is more important than pronouncability.

I take it from this that you assume that hungarian notation is readable. Just as it isn't pronouncable it isn't readable either and for the same reason.

>> 5. Windows types

>> I made C++ projects on a Win3.11 platform. And i am very grateful that MS used this kind of notation. And it's good that MS hadn't changed it as some of these projects have been converted to Win32 projects and i still have to support them. if MS changes notation for .NET it's ok but it's an absolute must that the notation for SDK and MFC hasn't altered.

What I suspect you are most grateful is the fact that they didn't change whatever notation they were using. If they had not used hungarian notation in Win3.11 platform you would most likely be grateful that they did not introduce it in Win32. So it isn't the hungarian notation that is the good thing for you it is the fact that the environment was "almost the same". This was of course one of the premises that MS had to ensure in order to make people being willing to recompile and rebuild their applications for Win32 so I believe that would be true with or without hungarian notation. It is in other words completely irrelevant to the issue at hand.

>> 6. it really only works for a few selected predetermined types

>> That must not be true. In most projects i made there had been rules for private types as well. The pointer, member and static notation applies to all types. For private types you may use suffixes, e. g.  Person* pFirstPerson or Object anyObj. However, most benefits you get by prefixing or suffixing all standard types, especially pointers, e. g.  map<string, Person> personByNameMap, string strDescription, vector<int> intArr, const char * pcszName, char** pszArgs, ... If you would have done that consequently in most of your projects as i did, you wouldn't argue that it isn't useful.

Actually it IS true. The rules for private types are either

a) unused prefixes in the "standard" notation are set aside for private types. For example if company Foo has a type bar which is used all around a lot and they find that the prefix q is not used for anything in "standard" hungarian notation they can decide that qX indicate that X is of type bar and pqX is a pointer to a bar etc.

b) You put a suffix to indicate the type such as pXPerson or pYCustomer etc to be pointers to Person and Customer respectively.

Both of these solutions have their problems. The first one has obviously very limited use since only a few types can get an otherwise free prefix, once a type has taken it it cannot be used for other types.

The other solution looks nifty until you realize that mixing prefixes and suffixes like this might not be so smart, how do you pair a prefix and suffix?

pFooPerson is a pointer to a Person, ok?
FooPersonMap is a map of person objects, ok?

pFooPersonMap is that a map of pointers to person objects or is a pointer to a map of person objects?

I could go on and on, but I leave it at that.

Alf
I opened a new thread in

http:/Cplusplus/Q_20929050.html

and apologize to Pete that we spoiled his initial question.

Regards, Alex
Well , in my opinion, you should go for .Net if you have just started the the VC++. Because it is proven that it takes months to learn VC++ despite the matter whether you use API or MFC.

But if you must use VC++, then doing the API to some extent and migrating to MFC is the best choice. But do not get so crazy about API tangle, because its not gonna be supported in the future very much.

Got?

Regards.
pete_bristol,
You might want to look at:  http:/help.jsp#hi73
-- Dan