 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Michael K. O'Neill Guest
|
Posted: Mon Nov 06, 2006 3:58 am Post subject: Overriding/Redefining a Non-Virtual Function in Derived Clas |
|
|
In Scott Meyers' "Effective C++", item 36 states "Never redefine an
inherited non-virtual function". This admonition is repeated at item 23.8
of C++ FAQ Lite ("[23.8] Should a derived class redefine ("override") a
member function that is non-virtual in a base class?" at
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.8 ).
I only just now recognized that in the MFC framework, this is done all the
time. Particularly with respect to message handlers for CWnd-derived
classes, it's common to see code like:
BOOL CDerivedWnd::OnEraseBkgnd(CDC* pDC)
{
// call base class function, which is not a virtual function
CWnd::OnEraseBkgnd(pDC);
// ... code specific to derived class
return TRUE;
}
I recognize that MFC is not a paragon of C++ good-programming practices. It
is also my understanding that the programming of message handlers for
CWnd-derived classes was an attempt to *avoid* virtual functions.
But given the fact that it is used so extensively by the MFC framework, is
it truly such a bad idea to override/redefine non-virtual functions in
derived classes? Is it truly something that should be left to "experienced
C++ programmers", as mentioned in the C++ FAQ Lite?
Mike
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Mon Nov 06, 2006 10:10 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
Michael K. O'Neill ha scritto:
| Quote: | In Scott Meyers' "Effective C++", item 36 states "Never redefine an
inherited non-virtual function". This admonition is repeated at item 23.8
of C++ FAQ Lite ("[23.8] Should a derived class redefine ("override") a
member function that is non-virtual in a base class?" at
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.8 ).
I only just now recognized that in the MFC framework, this is done all the
time. Particularly with respect to message handlers for CWnd-derived
classes, it's common to see code like:
BOOL CDerivedWnd::OnEraseBkgnd(CDC* pDC)
{
// call base class function, which is not a virtual function
CWnd::OnEraseBkgnd(pDC);
// ... code specific to derived class
return TRUE;
}
I recognize that MFC is not a paragon of C++ good-programming practices. It
is also my understanding that the programming of message handlers for
CWnd-derived classes was an attempt to *avoid* virtual functions.
|
All the message handler machinery is just an attempt to have
virtual-like functions in a more manageable way (i.e.: more suitable to
address the specific problem) than the "standard" C++ virtual keyword.
So, in certain sense, MFC is still using some kind of virtuality. MFC
can't be taken as a general counter-example of EC++ item 36.
| Quote: | But given the fact that it is used so extensively by the MFC framework, is
it truly such a bad idea to override/redefine non-virtual functions in
derived classes? Is it truly something that should be left to "experienced
C++ programmers", as mentioned in the C++ FAQ Lite?
|
Well... Not that I like or endorse MFC, but you need a quite experienced
programmer to design something like the MFC message handler machinery.
The fact that the machinery is provided in library form so that even an
unexperienced programmer can use it out-of-the-box, doesn't mean the
advice of item 36 or the C++ FAQ Lite is wrong or invalid.
Just my opinion,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Bo Persson Guest
|
Posted: Mon Nov 06, 2006 10:10 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
Michael K. O'Neill wrote:
| Quote: | In Scott Meyers' "Effective C++", item 36 states "Never redefine an
inherited non-virtual function". This admonition is repeated at
item 23.8 of C++ FAQ Lite ("[23.8] Should a derived class redefine
("override") a member function that is non-virtual in a base
class?" at
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.8
).
I only just now recognized that in the MFC framework, this is done
all the time. Particularly with respect to message handlers for
CWnd-derived classes, it's common to see code like:
BOOL CDerivedWnd::OnEraseBkgnd(CDC* pDC)
{
// call base class function, which is not a virtual function
CWnd::OnEraseBkgnd(pDC);
// ... code specific to derived class
return TRUE;
}
I recognize that MFC is not a paragon of C++ good-programming
practices. It is also my understanding that the programming of
message handlers for CWnd-derived classes was an attempt to *avoid*
virtual functions.
|
This was done in a time when having large vtables was considered wasteful,
considering the few MBs a power user machine had available. We are talking
the previous millennium!
If the design was redone from scratch right now, there would surely be other
considerations.
| Quote: |
But given the fact that it is used so extensively by the MFC
framework, is it truly such a bad idea to override/redefine
non-virtual functions in derived classes? Is it truly something
that should be left to "experienced C++ programmers", as mentioned
in the C++ FAQ Lite?
|
Yes.
Why would you want to do that?
The MFC guys were forced to invent their own virtual-on-demand machinery, to
save some bytes in a memory constrained environment. Not recommended at
current time.
Bo Persson
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Frederick Gotham Guest
|
Posted: Mon Nov 06, 2006 10:10 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
Michael K. O'Neill:
| Quote: | But given the fact that it is used so extensively by the MFC framework,
is it truly such a bad idea to override/redefine non-virtual functions
in derived classes? Is it truly something that should be left to
"experienced C++ programmers", as mentioned in the C++ FAQ Lite?
|
I think this is a matter of opinion more than anything. There are a few
programmers here who scorn the use of arrays, while others such as myself
don't hesistate to use them.
I don't program by any rules, because any rule worth defining will be
abandoned at some stage. Judging by your post, it seems that you put much
weight in what Scott Meyers says, so in the end it's up to you to decide
whether to accept this as a programming rule.
If you have a broad knowledge of the facilities available to you when
programming in C++, you can use your own creativity and ingenuity to decide
how you're going to solve a problem.
I have overriden non-virtual functions a few times, particularly when I knew
that I wouldn't be needing polymorphism (or when I explicitly didn't want
polymorphism).
--
Frederick Gotham
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Neal Guest
|
Posted: Mon Nov 06, 2006 10:10 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
{ Please don't top-post, and please don't quote the clc++m banner. -mod }
I think the way MFC to override a non-virtual member is MFC's
simulation of virtuals in C++. Because MFC also use a message handling
mapping table to mapping a message to its handler in a specified class,
combining with the way to implement a dervied class's message handler,
it achieve the same result of overriding a virtual member.
Michael K. O'Neill wrote:
| Quote: | In Scott Meyers' "Effective C++", item 36 states "Never redefine an
inherited non-virtual function". This admonition is repeated at item 23.8
of C++ FAQ Lite ("[23.8] Should a derived class redefine ("override") a
member function that is non-virtual in a base class?" at
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.8 ).
I only just now recognized that in the MFC framework, this is done all the
time. Particularly with respect to message handlers for CWnd-derived
classes, it's common to see code like:
BOOL CDerivedWnd::OnEraseBkgnd(CDC* pDC)
{
// call base class function, which is not a virtual function
CWnd::OnEraseBkgnd(pDC);
// ... code specific to derived class
return TRUE;
}
I recognize that MFC is not a paragon of C++ good-programming practices. It
is also my understanding that the programming of message handlers for
CWnd-derived classes was an attempt to *avoid* virtual functions.
But given the fact that it is used so extensively by the MFC framework, is
it truly such a bad idea to override/redefine non-virtual functions in
derived classes? Is it truly something that should be left to "experienced
C++ programmers", as mentioned in the C++ FAQ Lite?
Mike
|
{ clc++m banner stripped -mod }
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Ulrich Eckhardt Guest
|
Posted: Mon Nov 06, 2006 10:10 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
Michael K. O'Neill wrote:
| Quote: | In Scott Meyers' "Effective C++", item 36 states "Never redefine an
inherited non-virtual function". [...]
I only just now recognized that in the MFC framework, this is done
all the time. Particularly with respect to message handlers for
CWnd-derived classes, it's common to see code like:
BOOL CDerivedWnd::OnEraseBkgnd(CDC* pDC)
{
// call base class function, which is not a virtual function
CWnd::OnEraseBkgnd(pDC);
// ... code specific to derived class
return TRUE;
}
|
This in fact is a virtual function, just that the virtual function dispatch
is not implemented in terms of C++ virtual functions but with an external
message map. However, still the same principles apply: when a message is
received, the MFC try to find a handler in the most derived class' message
map. If they find one, it is called, otherwise they try to find a matching
handler in the baseclass's message map (THE baseclass, which is why MFC
don't play too well with multiple inheritance).
Also, the same rule for overriding applies here. If you have a widget that
requires the message for a left mouse click, you shouldn't hide this
message when deriving from the widget, lest it behave unexpectedly. If at
all, you'd call the base-class implementation in your override (as you did
in above code snippet) before doing your own code (or sometimes after).
This style of extending a function is not done automatically by C++
virtual keyword, so adding virtual or removing it doesn't help here.
| Quote: | I recognize that MFC is not a paragon of C++ good-programming
practices. It is also my understanding that the programming of
message handlers for CWnd-derived classes was an attempt to
*avoid* virtual functions.
But given the fact that it is used so extensively by the MFC
framework, is it truly such a bad idea to override/redefine
non-virtual functions in derived classes? Is it truly something
that should be left to "experienced C++ programmers", as mentioned
in the C++ FAQ Lite?
|
Software development is making decisions. If your requirements show that
things get better (clearer, faster, more scalable, smaller, whatever) when
you do something that is generally frowned upon, you are free to decide
that this is still the way to go. The only thing I'd ask you to do is to
document this decision, in particular when it is non-obvious.
Uli
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Dilip Guest
|
Posted: Tue Nov 07, 2006 1:32 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
On Nov 6, 2:09 am, Frederick Gotham <fgotha...@SPAM.com> wrote:
| Quote: | If you have a broad knowledge of the facilities available to you when
programming in C++, you can use your own creativity and ingenuity to decide
how you're going to solve a problem.
|
This is one point I totally agree with. I sometimes use that as an
excuse to feign ignorance about certain best practices that come under
GoF patterns (by claiming that if I put enough thought into it I
will probably come up with equivalent or better design independantly
).
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Richard Smith Guest
|
Posted: Tue Nov 07, 2006 1:33 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
Michael K. O'Neill wrote:
| Quote: |
In Scott Meyers' "Effective C++", item 36 states "Never redefine an
inherited non-virtual function".
|
(Actually, it's item 37, unless the items were renumbered between
editions.)
This is quite a different use case from the one you outline (or at
least, I think it is -- though I'm quite rusty on MFC), but I can think
of one situation where I've done this and I would argue it is
completely safe. In a parallel hierarchy implementation, it can
sometimes be useful to provide a non-virtual covariant accessor to the
parallel type. This example is a little contrived, but hopefully
serves to illustrate the point.
class Document {};
class Application {
public:
Document const& getDocument() const { return *mDoc; }
protected:
Application( Document* d ) : mDoc(d) { assert(d); }
private:
boost::scoped_ptr<Document> mDoc;
};
class MyDoc : public Document {};
class MyApp : public Application {
public:
MyApp() : Application( new MyDoc ) {}
MyDoc const& getDocument() const {
return static_cast<MyDoc const&>( Application::getDocument() );
}
};
The MyApp::getDocument function hides the one in the base class, but
this doesn't matter. The derived function is semantically the same as
the base class's -- the extra cast to return the derived MyDoc type is
no more than syntactic sugar.
Other than general design considerations (is it good design to allow
clients of MyApp to access directly the extended functionality of
MyDoc?), I can't any reason not to do this.
--
Richard Smith
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Andrei Alexandrescu (See Guest
|
Posted: Tue Nov 07, 2006 6:17 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
Dilip wrote:
| Quote: | On Nov 6, 2:09 am, Frederick Gotham <fgotha...@SPAM.com> wrote:
If you have a broad knowledge of the facilities available to you when
programming in C++, you can use your own creativity and ingenuity to decide
how you're going to solve a problem.
This is one point I totally agree with. I sometimes use that as an
excuse to feign ignorance about certain best practices that come under
GoF patterns (by claiming that if I put enough thought into it I
will probably come up with equivalent or better design independantly
).
|
At the risk of becoming mildly off-topic, I'd like to point out that
most people who successfully broke through the state of the art in any
domain were well versed in that state of the art. The risk of polluting
oneself with fallacious ways of doing things is overwhelmed by the
opportunity to gain a better view of a domain, be it C++, patterns, or
whatnot.
Andrei
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Tue Nov 07, 2006 10:10 am Post subject: Re: Overriding/Redefining a Non-Virtual Function in Derived |
|
|
Dilip wrote:
| Quote: | On Nov 6, 2:09 am, Frederick Gotham <fgotha...@SPAM.com> wrote:
If you have a broad knowledge of the facilities available to
you when programming in C++, you can use your own creativity
and ingenuity to decide how you're going to solve a problem.
This is one point I totally agree with. I sometimes use that as an
excuse to feign ignorance about certain best practices that come under
GoF patterns (by claiming that if I put enough thought into it I
will probably come up with equivalent or better design independantly
).
|
Sounds like a great recepe for unreadable code. And for code
which doesn't work, or requires a lot more effort to make work.
If there's a simple, effective solution to the problem, use it.
Don't reinvent the wheel.
--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|