abstract - Members modified by this keyword MUST be defined in an abstract class and be implemented on any concrete (non-abstract) class that extends the class the member is defined on. (This corresponds to the 'MustOverride' keyword in VB.NET.)
virtual - Members modified by this keyword CAN be overriden on a concrete class that extends the class that defines the member. (This corresponds to the 'Overridable' keyword in VB.NET.)
C# Example:
abstract class AbstractClass
{
protected void NotModifiedMethod() { }
protected abstract void AbstractMethod();
protected virtual void VirtualMethod() { }
}
class ConcreteClass : AbstractClass
{
//This HAS to be overriden because it's abstract
protected override void AbstractMethod() { }
//This CAN be overriden because it's virtual
protected override void VirtualMethod()
{
base.VirtualMethod();
}
//You CAN NOT do this, because NotModifiedMethod is not
//marked as abstract or virtual
protected override void NotModifiedMethod() { }
}
VB.NET Example:
MustInherit Class AbstractClass
Protected Sub NonModifiedMethod()
End Sub
Protected MustOverride Sub MustOverrideMethod()
Protected Overridable Sub OverridableMethod()
End Sub
End Class
Class ConcreteClass
Inherits AbstractClass
'This HAS to be overriden because it's marked MustOverride
Protected Overrides Sub MustOverrideMethod()
End Sub
'This CAN be overriden because it's marked Overridable
Protected Overrides Sub OverridableMethod()
MyBase.OverridableMethod()
End Sub
'You CAN NOT do this, because NotModifiedMethod is not
'marked as MustOverride or Overridable
Protected Overrides Sub NonModifiedMethod()
MyBase.NonModifiedMethod()
End Sub
End Class
13 comments:
Good point to raise, Peter, I see many new developers such as myself not using abstract classes enough.
Since I have been trying to bone up on design patterns, I am beginning to see the importance, and increase my reliance on abstract classes. They are VERY useful..
A good follow on to this may be to outline hook methods? They are a very powerful part of "abstract class programming", they can really help in creating abstract classes that are customisable and extensible?
Rob,
Inheritance has its place, but it's often overused. Just be careful about how you use it. One fundamental design principal is "Favor composition over inheritance". That principal can also be phrased like this "HAS-A can be better than IS-A". [Thanks to Head First Design Patterns for enlightening me on those ideas.] While it may not be as programmatically elegant, it's often technically and logically simpler to introduce functionality into a class by including another class as a member of it instead of trying to marry the new stuff into a super class.
Of course, I tend to use abstract classes more for the "Interface" (not as in an actual interface, but as you say, using it to compose objects of "generic" types rather than concrete classes..
I too am also a great fan of head first design patterns ;)
In my comment I was referring more to the "Hollywood Principle" (don't call us, we'll call you), I believe it gets a mention once or twice in HFDP.. Where you can use hook methods to allow subclasses to add customised logic in between steps within the superclass, this may be some form of environment preparation (or whatever). I found that this simple construct allows you to create generic classes that may not always be immediately obvious, and if required, can later be refactored to remove any bad smells.
Isn't that rather the point of abstract methods? The super class defines methods that it will call at some point and it's up to the sub class to provide the concrete implementation. This and the "Hollywood Principle" are defined in the "Template Pattern" section of the HFDP book (~page 289). Good catch.
Thank you for the article, that helps me a lot. As an C# newbie, I have a lot to get familiar with. Cheers!
In few words it is expaining lots of.Thank you.
Very nice and short article with a clear point. I read it because I was not sure on the issue.
However, I would just like to add something that can be easily concluded from what is written and what you could have mentioned in there:
1) A class with an abstract method must be abstract as it doesn't have the implementation for one of its methods.
2) A virtual method is sort-of default implementation which can be overridden. Thus, when there is a virtual method, the compiler acts as follows (in any inherited class):
- if there is no override it uses the method from parent class (default implementation)
- if there is override it uses the overridden method from the inherited class.
Thanks for the post and article. I'm a newbie to C# and this def. helped clear up the confusion i had between abstract & virtual modifiers.
I still don't see the point of virtual. Since you can override a non virtual method, what's the point of having virtual at all?
I like the Is A? approach... a lot of developers (not many senior but a lot of junior) don't seem to adopt this approach. Case in point: I just spoke to someone not too long (read: in the last day) about why that kind of approach is important.
With regards to abstract versus virtual. In my opinion, it tends to be a case of 'does this action need to have an initial value (aka virtual) or is it really implicit (aka abstract and the whole world will implode in on itself if this method is not implemented).
I think that is where sometimes developers fail to define the actual implementation.
I like the Is A? approach... a lot of developers (not many senior but a lot of junior) don't seem to adopt this approach. Case in point: I just spoke to someone not too long (read: in the last day) about why that kind of approach is important.
With regards to abstract versus virtual. In my opinion, it tends to be a case of 'does this action need to have an initial value (aka virtual) or is it really implicit (aka abstract and the whole world will implode in on itself if this method is not implemented).
I think that is where sometimes developers fail to define the actual implementation.
Just another point: The 'has a' and 'is a' principle is a fine point and tends to be a focal point of what needs to be implemented in a particular application. The gact of the matter is, it is about what works the best and what is required by the client (welcome to the real world )... @ Peter and Rob ... :|
The explanation given here for 'virtual' is incomplete and very misleading.
If a base class defines draw() as virtual then the version of draw() that is actually called at runtime is determined at runtime, based upon the actual runtime type of the object instance in question (rather than the type of the object reference you have in hand, which is often of the base type).
If draw() is *not* virtual then the version of draw() that is called at runtime is determined at compile time, and is based solely upon the type of object reference you have in hand.
For example, let's say that Circle derives from Shape (neither is abstract) and Shape defines a non-virtual draw() method that is overridden in Circle.
Shape *s1 = new Circle();
s1->draw(); // will call Shape::draw()
If instead, Shape's draw() method is virtual then:
Shape *s2 = new Circle();
s2->draw(); // will call Circle::draw()
A big difference!
Post a Comment