Herb Sutter: never make virtual functions public(!)
If you look at the C++ standard library then you see this pattern everywhere, take the ctype locale class for example, is(...) calls the protected virtual method do_is(...). It's the same with the stream buffer classes too, pubseekoff() calls the virtual protected function seekoff().
Quote:Original post by petewoodQuote:Original post by MichaelT
I am more interested in why he is suggesting this (His thinking behind it, why he consider it to be good style?) Personally, I consider it good style to hide anything that users of that class have no use for.
Right, you would like to have no dependency on private details:
*** Source Snippet Removed ***
*** Source Snippet Removed ***
Quote:Original post by petewoodBut just using the template pattern (if I'm understanding what that means correctly), you'd still store a group of 'Shape's even if you used public virtual methods in the implementation normally:
[...]But in my example you have a Non-Virtual Interface (NVI as Herb calls it), which you store in your containers.
So you have a container of Shape objects rather than a container of Shape*
*** Source Snippet Removed ***
class ShapeImpl;//the main class that will be used all over your programclass Shape {public: void Draw(DrawingContext&); void SetImplementation(std::auto_ptr<ShapeImpl>);private: ShapeImpl* m_pImpl;};class ShapeImpl {public: virtual void Draw(DrawingContext&) = 0;}
A 'shape' is just a different way of saying 'ShapeImpl *' in either case (as far as I can tell). Why have the extra level of redirection in ShapeImpl?
Quote:Original post by Magmai Kai Holmlor
(and private virtuals are generally silly, maybe a private virtual dtor in unusual/rare cases).
Actually, his reasoning behind using private virtuals is very sound. (See guidlines #2 and #3). If the child class should not be directly invoking the method, then there is no reason for it to be able to. Hence why it should be private virtual and not protected virtual.
Quote:Original post by snk_kid
I think you've miss-understood me, for one i'm not for or against it i was giving a reason why Herb would suggest to do this.
No, I wasn't misunderstanding you - I just used your post as a basepoint for futur developments :)
Quote:Original post by Washu
Actually, his reasoning behind using private virtuals is very sound. (See guidlines #2 and #3). If the child class should not be directly invoking the method, then there is no reason for it to be able to. Hence why it should be private virtual and not protected virtual.
Sounds logical - but why private virtuals then ? As I see it, virtuals are used to allow behavior modifications in a child class. Since the method is private, the child class do not even see it, therefore cannot inherit from it, therefore cannot redefine its behavior. Do I miss something ?
Quote:
"Traditionally, many programmers were used to writing base classes using public virtual functions to directly and simultaneously specify both the interface and the customizable behavior."
and so on... (see Magmai Kai Holmlor's post)
Make sense : the goal seems to be the separation of interface and behavior. I think (I maybe wrong, I'm not a design guru) that this is not that interesting. When you specify the interface of an object, you actually specify how he reacts to external stimulis (methods are refered as messages in the object programming terminologies, and therefore are used to react to messages). If your object provides an abstraction layer (say : an Animal class), it actually tells to the user (this user being a program) what are the messages that can be sent to it, without specifying how it will answer these messages. Intuitivelly, having a non virtual "move" function in an abstract Animal class tells me that any Animal will move exactly the same way. Too bad a bird cannot fly when a cat tries to catch it :P.
As I understand it, Sutter's point may add more complexity to my code without any reward.
Again, I may miss something important here.
Regards,
Quote:Original post by Emmanuel Deloget
Sounds logical - but why private virtuals then ? As I see it, virtuals are used to allow behavior modifications in a child class. Since the method is private, the child class do not even see it, therefore cannot inherit from it, therefore cannot redefine its behavior. Do I miss something ?
if a virtual member function is private sub-types can implement/override but cannot access/use the method.
Quote:
Sounds logical - but why private virtuals then ? As I see it, virtuals are used to allow behavior modifications in a child class. Since the method is private, the child class do not even see it, therefore cannot inherit from it, therefore cannot redefine its behavior. Do I miss something ?
No, you can override a private virtual, but you could never call it in your inherited class. See cpptip on private virtual.
Quote:Original post by Emmanuel Deloget
Sounds logical - but why private virtuals then ? As I see it, virtuals are used to allow behavior modifications in a child class. Since the method is private, the child class do not even see it, therefore cannot inherit from it, therefore cannot redefine its behavior. Do I miss something ?
As snk_kid said, a private virtual function can be overriden by derived classes, they cannot be directly called by derived classes however.
@snk_kid, risingdragon3, Washu : it seems that I actually missed something :)
As a consequence (short abstract of the whole stuff ?):
A) needs
B) results
Conclusion : as always, I'll have to take our code base and modify a lot of things. Nothing more than 10 days of grunt work :/. Thanks everyone, now I know that I will never return to my home... [depressed]
Regards,
As a consequence (short abstract of the whole stuff ?):
A) needs
- if I do not need to call my parent's function, I make the virtual function private.
- if I need to call it, I make it protected
- I add a public stub method that calls the virtual function in the base class.
- I only use the non-virtual public stub.
B) results
- correct (semantic) separation of customizable behavior and interface
- no efficiency problem (in most cases, the stub method can be inlined, so you end up with the same binary code)
- no code complexity problem (I said the contrary, I know) because only the base class contains more code, and this code is rather simple
- possibility to slightly modulate the code inside the non-virtual stub function (adding pre/post condition checks)
- (lot of other significant pros, just read Sutter's article)
Conclusion : as always, I'll have to take our code base and modify a lot of things. Nothing more than 10 days of grunt work :/. Thanks everyone, now I know that I will never return to my home... [depressed]
Regards,
Quote:Original post by Emmanuel Deloget
@snk_kid, risingdragon3, Washu : it seems that I actually missed something :)
As a consequence (short abstract of the whole stuff ?):
A) needs
- I only use the non-virtual public stub.
This isn't quite correct. The public function can be virtual (think interfaces), it's just not virtual for the purpose of exposing plugable functionality to the derived class, but for exposing a common public interface (ie COM).
Yeah i wouldn't go over the top with-it i think it needs careful planning doing something like this:
i don't see it very useful as flexible as it maybe but when used with template method:
is a powerful technique. Open up your implementation of std::basic_streambuf then look at std::basic_filebuf/std::basic_stringbuf to see this being done.
class base_foo { virtual int do_bar() const = 0;public: int bar() const { return do_bar(); }};class dev_foo : public base_foo { int do_bar() const { return 30; }};
i don't see it very useful as flexible as it maybe but when used with template method:
Quote:
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. TemplateMethod lets subclasses redefine certain steps of an algorithm without changing the algorithms's structure.
is a powerful technique. Open up your implementation of std::basic_streambuf then look at std::basic_filebuf/std::basic_stringbuf to see this being done.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement