Re: Not pure virtual functions and mixing virtual and non virtual methods
- From: Sasa <sasa555@xxxxxxxxx>
- Date: Wed, 30 Aug 2006 21:37:02 +0200
Daniel T. wrote:
In article <ecsiil$46c$1@xxxxxxxxxxxxxx>, Sasa <sasa555@xxxxxxxxx> wrote:
I should have probably provided more details of what I was thinking.
Sasa wrote:
Hello everybody,
I realize this has partially been mentioned in some other threads, but I would like to read your explicit oppinion in the separate thread.
Currently I have following oppinion:
a) Virtual method which is not pure (i.e. which has implementation) is usually a bad idea.
Yes (responding to H.S.L.), this is stated with C++ in mind. Let us assume that base class has virtual method with implementation. What happens in the derived class when overriding the method? Should I call base class implementation or not? If yes, when - before or after my overridden code is invoked?
Those of course are important questions that depend on context. Different derived classes may require different answers.
These questions lead me to believe that such design is fragile and confusing. It seems to me that it can usually be resolved in a more straightforward way by breaking the code in two methods - non virtual method in the base and pure virtual (abstract) method which must be overridden by the implementation.
But doing the above assumes that one answer is good for all, that all derived classes will want the base class method called in the same way.
Not really. In doing the above, the developer of the base class has the chance to enforce her decision via code (rather than via comments). If something must be invoked, it can be put in the sealed (not overridable) class. If something may or may not be invoked - another class can be created which offers services for the derived implementation. The developer of the implementation can decide whether to invoke or not those services.
This might not be the case (and the Base class designer won't know because all possible derived classes haven't been created yet.)
In MSDN I often see the statement "Make sure you call the base implementation". This seems like the case which base class designer knows. Other than that, if something is optional, it can be provided as the service, and left to the developer to call or not to call.
b) Deriving from the class which contains non virtual methods is usually bad idea.
See for example GoF Factory Method pattern, the first diagram. The Application class has three Methods:
CreateDocument()
NewDocument()
OpenDocument()
The first is abstract, the other two are not virtual.
Why couple these methods in the same class? Why not introduce the interface IDocumentCreator with the CreateDocument methods, and have the Application receive the implementation of IDocumentCreator via parameter (either constructor or any relevant method)?
I think you should reverse your questions. Why not couple these methods? After all they all have to do with Documents in the contexts of the Application. Why create a separate interface class that MyApplication must derive from and the be forced to pass it to the Application object? It's not like the method's behavior must change mid-program.
I'm thinking that if something is variant, it is really a separate responsibility. What I see here are two responsibilities:
1. The application which deals with documents.
2. The creation of the document.
Consider following: what if application has to create different types of documents. How will you deal with it. Sure in this example, you can put an if in the CreateDocument. But the question is why the polymorphic application class over the CreateDocument method when you still have to put ifs in the polymorphic method.
More generally, the way I see it, if you combine invariant implementation with variant parts, you have no elegant way to change the variant part. Of course, one doesn't know upfront if this is needed. However, I think it's not much more complicated to extract the variant part to another class. What you get for free is the possibility at any time to change the variant part in the runtime. By combining invariant/variant in one class, I don't see how you have it.
When some parts of class must be made polymorphic, it seems to me that it is usually good idea to move those parts in separate pure interface.
Your rules basically avoid inheriting implementation. Think about your rules in the context of a dynamic language rather than a purely C++ stance. Following them will remove all inheritance relationships. Do you believe that inheritance is so useless that it is only good for ensuring static type safety?
I'm not sure where you're going there. However, I have no experience with dynamic languages.
In any case, in my statically typed world, I see inheritance as the way to decouple the client (of an interface) from the implementation, in order to provide variable implementations.
I am happy to agree that in C++ and other static typed languages, the fact that inheritance is doing double duty is a pain in the ass, so maybe your rules make sense in that context. When discussing them, you might want to make sure the context is understood then.
Thank you for that comment. Yes, I was talking about statically typed OO (C++/C# being the languages I work in).
Sasa
.
- Follow-Ups:
- References:
- Prev by Date: Re: yet another deriving question
- Next by Date: Re: yet another deriving question
- Previous by thread: Re: Not pure virtual functions and mixing virtual and non virtual methods
- Next by thread: Re: Not pure virtual functions and mixing virtual and non virtual methods
- Index(es):
Relevant Pages
|