C++ Protected Members and MFC
Brad Wilson -- bradw@netnet.net
Friday, December 15, 1995
I'm sending this message in response to some back-channel discussion
that's been going on regarding my "(protected is evil :-)" comments
earlier this week to the list. This is related to MFC in a vague way
in that it came from the MFC implementations of toolbars, etc.
I believe I conveyed the wrong opinion about protected members. It
is never my intent to mislead anybody ... programming is hard enough
without having people to secretive about it :-).
Protected members and methods are meant to be used by those people who
implement child classes from the original class. In the case of MFC,
the structure was not documented (and there were stern warnings about
changes to the underlying structure) and thus shouldn't have been used.
But I don't fault the person who used it, since it's a perfectly legal
thing to do, given the "protected" status of the variable. It's very
easy to presume that it was not documented because it was missed, and
very easy to miss the stern warnings. The only thing that is concrete
proof of the intent of the member was its protected status.
When you code something that is volatile (like that structure was/is),
there should be no good reason to make it protected. If your users need
access to it or some of its members, you should provide protected methods
to access them, so that when the underlying volatile structure changes,
you can easily adapt to it.
The fact that it was not documented doesn't excuse the poor programming
practice. The fact is, it should have been private. Period. In this
case, there is without a doubt no excuse, because the given warnings
indicated that they knew the structure would be changing.
A lesson for all ... if you're not willing to document your protected
members and methods, they shouldn't be protected. They should be private.
You should almost NEVER make members protected ... you should always
shroud them in methods that, in the early stages, will cost nothing,
since they should simply be inline functions that return pointers or
references to the structure. That way, if and when structures change
(as they always do), you won't break anyones code.
--
class CBradWilson : public CWorldWatchProgrammingTeam {
public:
CString GetInetAddr() { return CString("bradw@exptech.com"); }
CString GetPhone() { return CString("+1 (810) 620-9803"); }
CString GetURL() { return CString("http://www.exptech.com"); }
CString GetDisclaimer() { return CString("All I say is fact :-p"); }
};
"All we have to do now, is take these lies and make them true somehow
All we have to see, is that I don't belong to you, and you don't
belong to me."
Eric Kenslow -- kenslowe@internet.OIT.OSSHE.EDU
Wednesday, December 20, 1995
[Mini-digest: 3 responses]
I'm afraid you are wrong. If you want to make something 'forbidden', =
and therefore inaccessible, you make it private. If you expect and =
allow others to modify it, you make it protected. This is a rule of =
C++, not MFC, and the members of the MFC group are the ones who screwed =
up, certainly not the persons who used their code.
Protected means 'yes derived classes, use this as it's not going to =
change'. Private means 'never use this, no matter how desperate you =
are.' This is a design decision, and obviously someone was asleep at =
the wheel here.
-----From: dhoward@kset.com
I have a different take on this subject.
C++ does not directly address the issue of backward compatibility inside
code. It is up to the author of the code to provide a mechanism for
backward compatiblity if he desires it. The MFC team's solution is not
great but it works for people who are very concerned about compatibility.
I have to strongly disagree with making most members private. When somebody
inherits from your class, you want to provide them as much rope as possible
but, at the same time, prevent them from hanging themselves.
Generally, providing Get() and Put() methods for accessing private data is
ineffective because the parameters and return values of the methods usually
imply the structure of the data. If you see a protected method prototype
such as "CString GetName();", the fact that the "name" string is stored as a
CString is not exactly hidden. If the underlying represention of "name"
changed from a CString to an integer in the next version, you would be in as
much trouble as if you let your data member hang out in the protected
section. The only way around this is to make your own class, CName, such
that the method prototype would be "CName GetName();" and then you could do
whatever you want. Unfortunately, if you take this approach, you will
quickly be buried in your own types and you might never get around to doing
any programming.
My rule of thumb is to make most everything protected. Your classes should
be written in such a way that if a protected data member has its value
changed, the class should handle the change smoothly when it detects the
change. For example, if you have a dialog box class which has a protected
data member which represents the border style and that data member is
modified while the dialog box is running, the dialog box should not crash
because it expects the data member to be same as it was initialized. The
class should display the new border style at the next time at the next time
that it is convenient (i.e. the dialog box is repainted).
The only time that you should use a private member is when you have two
pieces of data that need to remain synchronized. For example, if you are
creating a string class and you have a integer that caches the length of the
string (so you don't have to call strlen() all the time) and you have a
boolean that tells whether the cache is valid, these two values work in
tandem. When the integer is updated, the boolean must be updated as well.
Mucking with the boolean could cause the class to malfunction and you want
to prevent the inheritor of your class from setting the boolean to TRUE when
the integer contains garbage. So, you should put the integer and the
boolean in the private section and provide protected functions which force
their values to remain in sync.
By following these rules, I give the inheritor of my class maximum
flexibility while preventing the few situations where, at best, he can only
electrocute himself.
-----From: "Mike Blaszczak"
No; it needs to be protected. Someday, it _will_ be documented and some day
you _will_ be able to override it and get something interesting done. In a
commercial library like MFC, you can't make everything "private" because
people would complain--you're short-circuiting their ability to derive their
own classes and change things they don't dig.
Ideally, non-implementation things that are interesting only to a class (or
subclasses of that class) would always be protected. But in an ideal world,
not only do you have all of the memory you need... you also have a huge,
tireless documentation staff that documents everything you write. Even people
at Microsoft live in the real world--where things must be made "protected"
instead of "private" for other than idealistic reasons, and where things can't
always be documented even if they really _should_ be "protected".
.B ekiM
---------
From: owner-mfc-l@netcom.com on behalf of Brad Wilson
Sent: Friday, December 15, 1995 11:04
To: 'mfc-l@netcom.com'
Subject: C++ Protected Members and MFC
The fact that it was not documented doesn't excuse the poor programming
practice. The fact is, it should have been private. Period. In this
case, there is without a doubt no excuse, because the given warnings
indicated that they knew the structure would be changing.
Brad Wilson -- bradw@netnet.net
Thursday, December 21, 1995
dhoward@kset.com said ...
>> Generally, providing Get() and Put() methods for accessing private data is
>> ineffective because the parameters and return values of the methods usually
>> imply the structure of the data. If you see a protected method prototype
>> such as "CString GetName();", the fact that the "name" string is stored as a
>> CString is not exactly hidden.
The fact that it is locally stored is not implied at all. Presume
that your class keep "CString m_sName" as a private and provides
"GetName( CString& )" to get access to it. Now presume that the
name changes from time to time and you don't always know when it
changes (though you can poll to find out the name). Now, if you
have provided them direct access to m_sName, you would break
code. In the latter case, you can use the call to GetName()
to make your API call(s) to find out the "current" name.
Does this better illustrate why this is good? And keep in mind
that inline functions don't cost anything. That's why its usually
good to keep data hidden and provide access methods.
>> If the underlying represention of "name"
>> changed from a CString to an integer in the next version, you would be in as
>> much trouble as if you let your data member hang out in the protected
>> section.
Not necessarily. GetName() could still provide a CString representation
of the name (if this is appropriate), as well as overloading it to give
you an integer representation as well.
>> For example, if you have a dialog box class which has a protected
>> data member which represents the border style and that data member is
>> modified while the dialog box is running, the dialog box should not crash
>> because it expects the data member to be same as it was initialized.
Does your dialog box poll for changes to this variable to change its
visible style? Wouldn't a SetStyle() function be more prudent?
>> The
>> class should display the new border style at the next time at the next time
>> that it is convenient (i.e. the dialog box is repainted).
You would force them to repaint the whole dialog just to get the
new border style?
>> The only time that you should use a private member is when you have two
>> pieces of data that need to remain synchronized.
I definitely disagree with this. Private data should be used
for anything that is potentially volatile.
I would highly recommend you read "Code Complete" by Steve
McConnell. He has some excellent reasons for many of the things
that I've told the list about. His book is invaluable, next to
a book like Booch.
Mike B then said ...
>> Someday, it _will_ be documented and some day
>> you _will_ be able to override it and get something interesting done.
To steal your quote, "the future is not today". :-)
>> In a
>> commercial library like MFC, you can't make everything "private" because
>> people would complain--you're short-circuiting their ability to derive their
>> own classes and change things they don't dig.
Who said anything about "everything"? Who said anything about
people not being able to get to things? I merely suggested that
people "wrap" their volatile data structures in methods. The
"MFC design philosophy" has already burned one person. A "C++
design philosophy" might've helped to prevent it.
I would highly recommend you read "Code Complete" by Steve
McConnell (Microsoft press, hint hint :-).
Brad
John & Annette Elsbree -- elsbree@msn.com
Saturday, December 23, 1995
From: owner-mfc-l@netcom.com on behalf of Eric Kenslow
> I'm afraid you are wrong. If you want to make something 'forbidden', =
> and therefore inaccessible, you make it private. If you expect and =
> allow others to modify it, you make it protected. This is a rule of =
> C++, not MFC, and the members of the MFC group are the ones who screwed =
> up, certainly not the persons who used their code.
There are cases in which using protected, or even public, on implementation
details is useful (see excerpt below).
> Protected means 'yes derived classes, use this as it's not going to =
> change'. Private means 'never use this, no matter how desperate you =
> are.' This is a design decision, and obviously someone was asleep at =
> the wheel here.
What is your source for this definition for "protected"?
Nobody was "asleep at the wheel." MFC just has a different interpretation of
"protected" than you do. I refer you to the topic "MFC: Using the MFC Source
Files" in the MFC Encyclopedia (included as part of the VC++ documentation):
The most important section is the // Implementation section.
This section houses all implementation details. Both member variables and
member functions can appear in this section. Everything below this line could
change in a future release of MFC. Unless you cant avoid it, you should not
rely on details below the // Implementation line. In addition, members
declared below the implementation line are not documented, although some
implementation is discussed in technical notes...
Notice from the CStdioFile listing under An Example of the Comments that
members declared below the // Implementation comment may be declared as
public, protected, or private. The point is that you should only use these
members with caution, because they might change in the future. Declaring a
group of members as public may be necessary for the class library
implementation to work correctly. However, this does not imply that you may
safely use the members so declared.
mfcTeam.m_johnels; // does not represent Microsoft
Mark F. Fling -- mfling@mail.stratacorp.com
Sunday, December 24, 1995
> Generally, providing Get() and Put() methods for accessing private data is
> ineffective because the parameters and return values of the methods usually
> imply the structure of the data. If you see a protected method prototype
> such as "CString GetName();", the fact that the "name" string is
> stored as a CString is not exactly hidden.
^^^^^^
Really? What if "name" is stored on a DBMS located a continent
away, requires locking to protect it, and is cached within the class
thus requiring conditional read/update? Client/server classes
routinely provide accessor/operation methods to "get/set" that extend
far beyond the machine boundary and hide the whereabouts, type, and
concurrency of a class attribute.
If I public'ed these member variables, and you get/set them directly,
you probably would corrupt the database over time. In this scenario the
"attribute" is really a member variable AND some code to enforce
integrity. A good case for private/protected, would'nt you say?
___________________________________________________________________________
Mark F. Fling mfling@stratacorp.com
Strata Corporation / SBA Voice (805) 967-3051
922 Via Brocha Fax (805) 967-8203
Santa Barbara, CA 93110
dhoward@kset.com
Tuesday, December 26, 1995
I have read Steve McConnell's Code Complete. It is a respectable book.
Mike B.'s point is that the MFC team cannot predict the goals of every user
of the library. Rightly, MFC does to force compatibility on the users who
aren't interested in it. Recompiling without any changes in the new version
is an important goal for some people, not so important to others and
unimportant to others. Some programmers are going to want full access.
They're going to want to tweak MFC to do things that the creators did not
anticipate. The only way to satisfy these people is to have most everything
as protected.
It is the now old issue of "object bloat" as described by Taligent, Inc. Is
it worthwhile to hide all data members behind Get() and Set() methods?
My conclusion is: most of the time, it is not. The Get() and Set() methods
usually imply the structure of the data. It creates more code and more code
is more expensive to maintain. Hiding data behind a Get() method will allow
a few more options but it still is a rather limited approach to data
encapulation.
An example: CDocument::GetPathName() returns a CString. This implies that
pathnames are stored as strings. On the Mac, pathnames are usually stored
as FSSpec's. So, to use the Mac Portability Library, the programmer has to
go through contortions (e.g. WrapFile()) to convert the Mac filename in the
CString into a FSSpec. If CDocument::GetPathName() returned CFileName,
WrapFile() would not be necessary. Sure, GetPathName() provided a little
protection. But the MFC team realized that the Mac file structure does not
follow the assumption that a pathname is a string. To keep compatibility
with the old stuff, they had to keep that assumption and (basically,
although I am not blaming them) hack the FSSpec into a CString.
Jeff Dickey -- jdickey@sevensigma.com
Wednesday, December 27, 1995
-----BEGIN PGP SIGNED MESSAGE-----
All right guys, this has gone on long enough. Data members have NO
BUSINESS WHATEVER being public or even protected -- inline
accessor/modifier methods still buy you room to fiddle in the future.
Anybody who's ever worked on a large project ought to know this through
(probably painfully acquired) experience.
Just as one example, Stroustrup winds up a discussion of
private/public/protected in "Design and Evolution of C++" (p. 302) as:
"Fortunately, you don't have to use protected data in C++; 'private'
is the default in classes and is usually the better choice. Note
that none of these objections [protected data members being subject
to "users poking where they shouldn't in ways that they ought to
have known better than"] are significant for protected member
_functions_. I still consider 'protected' a fine way of specifying
operations for use in derived classes".
The embedded quote (from Mark Linton, implementor of InterViews, on why
he banned protected data members in InterViews) is uncannily
appropriate to MFC. I had been programming in Windows for several
years and in C++ on other platforms prior to my first exposure to MFC.
It has always seemed to me as if MFC 1.0 was written in a dead hurry by
a larger-than-optimal team with gonzo Windows and C knowledge, but who
had never done a large-scale C++ application. The abuse of the
protection scheme was one 1.0 legacy that we're all living with. I
have done at least five major (full- scale, implement pilot project in
each) framework evaluations over the last three for clients using a
variety of criteria; whenever clean class design and implementation was
any factor at all in the evaluation, MFC has uniformly placed at or
near the bottom. It scares me beyond words that companies are building
consumer-level or stability-critical applications using that framework
because it dramatically increases the costs and complexity of the
project without any concomitant increase in stability or
functionality. Microsoft had a chance to fix a lot of things in MFC
4.0 -- people could have swallowed broken code if the replacement was
obviously better -- but once again, the ball was never even picked up,
let alone dropped.
We really need to demand that Microsoft:
- quit trying to implement Smalltalk in their C++ library;
- provide a clean set of small, easily-understood classes which can
be used to leverage an application system, not just give a "me-too"
Windows interface;
- adhere to established, non-proprietary standards (ANSI draft as
benchmarked by major compliance suites such as Plum Hall);
- get rid of the macro-based abortions which can be replaced by ANSI
functionality which has been stable for quite some time (namespaces
are supported in 4.0; why doesn't 4.0 use standard casting
operators rather than macros? typesafe casting has been in the
spec a _lot_ longer);
- etc. etc. etc.
If Microsoft wants to get everybody to write closed, proprietary code,
they should stop trying to make it sound as if reusability and
portability are features which they offer.
Just my 0.0143254325 (damn Pentium bug!) after doing battle with M$ and
doing work with other stuff...
Jeff Dickey
- -- In Reply To
>I have read Steve McConnell's Code Complete. It is a respectable book.
>
>Mike B.'s point is that the MFC team cannot predict the goals of every user
>of the library. Rightly, MFC does to force compatibility on the users who
>aren't interested in it. Recompiling without any changes in the new version
>is an important goal for some people, not so important to others and
>unimportant to others. Some programmers are going to want full access.
>They're going to want to tweak MFC to do things that the creators did not
>anticipate. The only way to satisfy these people is to have most everything
>as protected.
>
>It is the now old issue of "object bloat" as described by Taligent, Inc. Is
>it worthwhile to hide all data members behind Get() and Set() methods?
>
>My conclusion is: most of the time, it is not. The Get() and Set() methods
>usually imply the structure of the data. It creates more code and more code
>is more expensive to maintain. Hiding data behind a Get() method will allow
>a few more options but it still is a rather limited approach to data
>encapulation.
>
>An example: CDocument::GetPathName() returns a CString. This implies that
>pathnames are stored as strings. On the Mac, pathnames are usually stored
>as FSSpec's. So, to use the Mac Portability Library, the programmer has to
>go through contortions (e.g. WrapFile()) to convert the Mac filename in the
>CString into a FSSpec. If CDocument::GetPathName() returned CFileName,
>WrapFile() would not be necessary. Sure, GetPathName() provided a little
>protection. But the MFC team realized that the Mac file structure does not
>follow the assumption that a pathname is a string. To keep compatibility
>with the old stuff, they had to keep that assumption and (basically,
>although I am not blaming them) hack the FSSpec into a CString.
-----BEGIN PGP SIGNATURE-----
Version: 2.6.2
iQCVAwUBMOIStM5EtwLVuV0NAQFAUAP/djLNBWNFd8Y7P0VQxlxtJdgq0Ti6iqwp
OtY08ZX8wj/cd+b/lztys+JJMqGAzp3EBtyvWOOZVNnznHapn+YReToDnZ9DDftF
j9QvFXyKYT0m713M9qukxqmd3+CQB8GEjTCRWEpOqrDm2DxoxdAS+iUexnHaQCbj
CA0+GirppXA=
=ETus
-----END PGP SIGNATURE-----
Jeff Dickey
Seven Sigma Software and Services
PGP-secured mail encouraged!
finger 'jdickey@sevensigma.com' or 'http://www.sevensigma.com/keylist.html'
for PGP public key
Key fingerprint = "99 CA 69 E5 2C 95 E8 4E 7E B2 59 5E FB A5 C2 FD"
Mike Blaszczak -- mikeblas@msn.com
Thursday, December 28, 1995
Mike B.'s point is that the MFC team cannot predict the goals of every user
of the library.
It's sort of impossible, isn't it? You can't blame the MFC team if you run
naked through the park with a CSplitterWnd on your head. But products like
ladders have to have stickers on them that say "if you use this ladder in a
thunderstorm, you might die" so that the ladder company doesn't get sued.
Of course, some MFC classes have warning labels if you look at the *.H files.
Some people are used to seeing warning labels like "protected:" or "public:"
or "private:", but MFC actually tries to use more specific words like "//
implementation". The reason is very simple: it's something that escapes most
college students, and lots of people who have PhDs. The reson is efficiency:
you can't design things perfectly and expect them to be very very fast _and_
very very flexible.
Doesn't someone on MFC-L have a .sig that says "fast cheap good: pick two"?
It is the now old issue of "object bloat" as described by Taligent, Inc. Is
it worthwhile to hide all data members behind Get() and Set() methods?
Exactly. Didn't this list have a huge discussion about this earlier in the
summer?
Rightly, MFC does to force compatibility on the users who
aren't interested in it.
If you said this to my hero, John Elsbree, he would say to you "This sentence
no verb". Everbody makes gramatical errors (and some people have whole books
full of them), but the missing words in this sentence make it hard to
understand what the point of that paragraph is.
.B ekiM
TCHAR szDisclaimer[] = _T("These words are my own; I do not speak on behalf of
the Motion Pictures Association of America.");
----------
From: owner-mfc-l@netcom.com on behalf of dhoward@kset.com
Sent: Tuesday, December 26, 1995 09:27
To: mfc-l@netcom.com
Subject: RE: C++ Protected Members and MFC
I have read Steve McConnell's Code Complete. It is a respectable book.
Mike B.'s point is that the MFC team cannot predict the goals of every user
of the library. Rightly, MFC does to force compatibility on the users who
aren't interested in it. Recompiling without any changes in the new version
is an important goal for some people, not so important to others and
unimportant to others. Some programmers are going to want full access.
They're going to want to tweak MFC to do things that the creators did not
anticipate. The only way to satisfy these people is to have most everything
as protected.
It is the now old issue of "object bloat" as described by Taligent, Inc. Is
it worthwhile to hide all data members behind Get() and Set() methods?
My conclusion is: most of the time, it is not. The Get() and Set() methods
usually imply the structure of the data. It creates more code and more code
is more expensive to maintain. Hiding data behind a Get() method will allow
a few more options but it still is a rather limited approach to data
encapulation.
An example: CDocument::GetPathName() returns a CString. This implies that
pathnames are stored as strings. On the Mac, pathnames are usually stored
as FSSpec's. So, to use the Mac Portability Library, the programmer has to
go through contortions (e.g. WrapFile()) to convert the Mac filename in the
CString into a FSSpec. If CDocument::GetPathName() returned CFileName,
WrapFile() would not be necessary. Sure, GetPathName() provided a little
protection. But the MFC team realized that the Mac file structure does not
follow the assumption that a pathname is a string. To keep compatibility
with the old stuff, they had to keep that assumption and (basically,
although I am not blaming them) hack the FSSpec into a CString.
Mike Blaszczak -- mikeblas@interserv.com
Thursday, December 28, 1995
On Wed, 27 Dec 1995, Jeff Dickey wrote:
>We really need to demand that Microsoft:
> - quit trying to implement Smalltalk in their C++ library;
I don't get it.
.B ekiM
--
TCHAR szDisc[] = _T("These words are my own; I do not speak for Microsoft.");
jarvisb@timken.com
Friday, December 29, 1995
No! No! You don't *understand*!!!
Protected data members are *bad*! :(
Get-Set methods are *good*!! :)
*Public* data members are the Spawn of the Evil One!!!
Obviously, the answer is to launch a full-scale thermonuclear attack
on Redmond - take no prisoners - leave nothing behind but a fused
glass plain. DEATH TO THE INFIDELS!!!!!
It must be nice to have nothing to do but debate religious issues.
Sheesh.
Bob Jarvis
*************************** Attachment ***********************************
Date: 29 December 1995, 00:39:57 EST
From: Mike Blaszczak mikeblas at INTERNET
mikeblas@msn.com
To: mfc-l at INTERNET
mfc-l@netcom.com
Reply-To: mfc-l at INTERNET
mfc-l@netcom.com
Subject: RE: C++ Protected Members and MFC
Sender: owner-mfc-l@netcom.com
Mike B.'s point is that the MFC team cannot predict the goals of every user
of the library.
It's sort of impossible, isn't it? You can't blame the MFC team if you run
naked through the park with a CSplitterWnd on your head. But products like
ladders have to have stickers on them that say "if you use this ladder in a
thunderstorm, you might die" so that the ladder company doesn't get sued.
Of course, some MFC classes have warning labels if you look at the *.H files.
Some people are used to seeing warning labels like "protected:" or "public:"
or "private:", but MFC actually tries to use more specific words like "//
implementation". The reason is very simple: it's something that escapes most
college students, and lots of people who have PhDs. The reson is efficiency:
you can't design things perfectly and expect them to be very very fast _and_
very very flexible.
Doesn't someone on MFC-L have a .sig that says "fast cheap good: pick two"?
It is the now old issue of "object bloat" as described by Taligent, Inc. Is
it worthwhile to hide all data members behind Get() and Set() methods?
Exactly. Didn't this list have a huge discussion about this earlier in the
summer?
Rightly, MFC does to force compatibility on the users who
aren't interested in it.
If you said this to my hero, John Elsbree, he would say to you "This sentence
no verb". Everbody makes gramatical errors (and some people have whole books
full of them), but the missing words in this sentence make it hard to
understand what the point of that paragraph is.
.B ekiM
TCHAR szDisclaimer[] = _T("These words are my own; I do not speak on behalf of
the Motion Pictures Association of America.");
----------
From: owner-mfc-l@netcom.com on behalf of dhoward@kset.com
Sent: Tuesday, December 26, 1995 09:27
To: mfc-l@netcom.com
Subject: RE: C++ Protected Members and MFC
I have read Steve McConnell's Code Complete. It is a respectable book.
Mike B.'s point is that the MFC team cannot predict the goals of every user
of the library. Rightly, MFC does to force compatibility on the users who
aren't interested in it. Recompiling without any changes in the new version
is an important goal for some people, not so important to others and
unimportant to others. Some programmers are going to want full access.
They're going to want to tweak MFC to do things that the creators did not
anticipate. The only way to satisfy these people is to have most everything
as protected.
It is the now old issue of "object bloat" as described by Taligent, Inc. Is
it worthwhile to hide all data members behind Get() and Set() methods?
My conclusion is: most of the time, it is not. The Get() and Set() methods
usually imply the structure of the data. It creates more code and more code
is more expensive to maintain. Hiding data behind a Get() method will allow
a few more options but it still is a rather limited approach to data
encapulation.
An example: CDocument::GetPathName() returns a CString. This implies that
pathnames are stored as strings. On the Mac, pathnames are usually stored
as FSSpec's. So, to use the Mac Portability Library, the programmer has to
go through contortions (e.g. WrapFile()) to convert the Mac filename in the
CString into a FSSpec. If CDocument::GetPathName() returned CFileName,
WrapFile() would not be necessary. Sure, GetPathName() provided a little
protection. But the MFC team realized that the Mac file structure does not
follow the assumption that a pathname is a string. To keep compatibility
with the old stuff, they had to keep that assumption and (basically,
although I am not blaming them) hack the FSSpec into a CString.
-----From: Jeff Dickey
Mike,
The model/view/controller scheme and the Great God Object Mega-Superclass
both come from
Smalltalk. MVC fit into the general mindset, and CObject-equivalent was
meeded because
nobody knew any other ways to do dynamic late binding without _really_
slowing things
down.
Anyway, that's what I meant.
Jeff
Mike Blaszczak -- mikeblas@interserv.com
Sunday, December 31, 1995
On Fri, 29 Dec 95, wrote:
>Protected data members are *bad*! :(
>Get-Set methods are *good*!! :)
That's sort of confusing. If you have a protected data member, it's bad (you
told me so yourself) so I'll make it public. Then, I'll implement Get/Set
methods (since you said they were good). But why would I want Get/Set
methods for accessing public member variables? Just to make a bigger EXE?
>*Public* data members are the Spawn of the Evil One!!!
Oh, wait--public is impish and protected is bad. So, do you mean that all
data members should be _private_?
>Obviously, the answer is to launch a full-scale thermonuclear attack
>on Redmond - take no prisoners - leave nothing behind but a fused
>glass plain. DEATH TO THE INFIDELS!!!!!
I don't understand that, either. Why would you murder me, my friends, and
all of the innocent bystanders here in Redmond just because you have a
different opinion than some other people on the list? I really think you
need to get a little bit of help--before you know it, you'll be beating your
girlfriend over a trivial matter, or something.
Anyway, please make sure what you meant by your two seemingly contradictory
statements. I'd hate to think that my programming practices would get forty
or fifty thousand people killed!
[Seriously: I really take offense to this kind of posting. It is juvenile
and isn't productive; it isn't going to solve anything. It does nothing but
show that the poster is closed-minded and ineloquent. I have to wonder what
place a note like that has on a moderated list. And I'm not interested in
busting my ass on a product, going the extra mile to answer questions about
it in my "spare time", and then having people tell me they'd like to blow up
my neighborhood. If you don't like it, go buy Borland C++ and use OWL.
Then, at least, I'll just worry about myself when I'm in Scotts Valley, and
not when I'm at home or work.]
>It must be nice to have nothing to do but debate religious issues.
Some people learn to skate while others curse the ice. I guess others still
just blow up the pond, fish and all.
.B ekiM
--
TCHAR szDisc[] = _T("These words are my own; I do not speak for Microsoft.");
>*************************** Attachment ***********************************
>Date: 29 December 1995, 00:39:57 EST
>From: Mike Blaszczak mikeblas at INTERNET
> mikeblas@msn.com
>To: mfc-l at INTERNET
> mfc-l@netcom.com
>
>Reply-To: mfc-l at
INTERNET
> mfc-l@netcom.com
>Subject: RE: C++ Protected Members and MFC
>Sender: owner-mfc-l@netcom.com
>Mike B.'s point is that the MFC team cannot predict the goals of every user
>of the library.
>
>It's sort of impossible, isn't it? You can't blame the MFC team if you run
>naked through the park with a CSplitterWnd on your head. But products like
>ladders have to have stickers on them that say "if you use this ladder in a
>thunderstorm, you might die" so that the ladder company doesn't get sued.
>
>Of course, some MFC classes have warning labels if you look at the *.H
files.
>Some people are used to seeing warning labels like "protected:" or "public:"
>or "private:", but MFC actually tries to use more specific words like "//
>implementation". The reason is very simple: it's something that escapes most
>college students, and lots of people who have PhDs. The reson is
efficiency:
>you can't design things perfectly and expect them to be very very fast _and_
>very very flexible.
>
>Doesn't someone on MFC-L have a .sig that says "fast cheap good: pick two"?
>
>It is the now old issue of "object bloat" as described by Taligent, Inc. Is
>it worthwhile to hide all data members behind Get() and Set() methods?
>
>Exactly. Didn't this list have a huge discussion about this earlier in the
>summer?
>
>Rightly, MFC does to force compatibility on the users who
>aren't interested in it.
>
>If you said this to my hero, John Elsbree, he would say to you "This
sentence
>no verb". Everbody makes gramatical errors (and some people have whole
books
>full of them), but the missing words in this sentence make it hard to
>understand what the point of that paragraph is.
>
>.B ekiM
>TCHAR szDisclaimer[] = _T("These words are my own; I do not speak on behalf
of
>the Motion Pictures Association of America.");
>----------
>From: owner-mfc-l@netcom.com on behalf of dhoward@kset.com
>Sent: Tuesday, December 26, 1995 09:27
>To: mfc-l@netcom.com
>Subject: RE: C++ Protected Members and MFC
>
>I have read Steve McConnell's Code Complete. It is a respectable book.
>
>Mike B.'s point is that the MFC team cannot predict the goals of every user
>of the library. Rightly, MFC does to force compatibility on the users who
>aren't interested in it. Recompiling without any changes in the new version
>is an important goal for some people, not so important to others and
>unimportant to others. Some programmers are going to want full access.
>They're going to want to tweak MFC to do things that the creators did not
>anticipate. The only way to satisfy these people is to have most everything
>as protected.
>
>It is the now old issue of "object bloat" as described by Taligent, Inc. Is
>it worthwhile to hide all data members behind Get() and Set() methods?
>
>My conclusion is: most of the time, it is not. The Get() and Set() methods
>usually imply the structure of the data. It creates more code and more code
>is more expensive to maintain. Hiding data behind a Get() method will allow
>a few more options but it still is a rather limited approach to data
>encapulation.
>
>An example: CDocument::GetPathName() returns a CString. This implies that
>pathnames are stored as strings. On the Mac, pathnames are usually stored
>as FSSpec's. So, to use the Mac Portability Library, the programmer has to
>go through contortions (e.g. WrapFile()) to convert the Mac filename in the
>CString into a FSSpec. If CDocument::GetPathName() returned CFileName,
>WrapFile() would not be necessary. Sure, GetPathName() provided a little
>protection. But the MFC team realized that the Mac file structure does not
>follow the assumption that a pathname is a string. To keep compatibility
>with the old stuff, they had to keep that assumption and (basically,
>although I am not blaming them) hack the FSSpec into a CString.
>
>-----From: Jeff Dickey
>
>Mike,
>
>The model/view/controller scheme and the Great God Object Mega-Superclass
>both come from
>Smalltalk. MVC fit into the general mindset, and CObject-equivalent was
>meeded because
>nobody knew any other ways to do dynamic late binding without _really_
>slowing things
>down.
>
>Anyway, that's what I meant.
>
>Jeff
>
>
Dan L. Pierson -- dan@cthulhu.control.com
Tuesday, January 02, 1996
> From: "John Elsbree"
> Nobody was "asleep at the wheel." MFC just has a different interpretation of
> "protected" than you do. I refer you to the topic "MFC: Using the MFC Source
> Files" in the MFC Encyclopedia (included as part of the VC++ documentation):
>
> The most important section is the // Implementation section.
Good point, however I'd like to point out that the new VC++ 4.0
class-based editing feature does it's best to defeat this
convention. If you ask it to add a member, it will put the new
member immediately after the first "public", "protected", etc. in the
class definition (rather odd, since it adds everything else at the
last possible place).
Please take a strong suggestion that this (very nice) feature be
enhanced to support the MFC class structuring conventions, especially
since you folks recommend that we use them too (at least for MFC
extension classes).
Thanks,
Dan Pierson
Control Technology Corporation
Dan Pierson, Control Technology Corporation,
| Вернуться в корень Архива
|