7.10 Method overriding using the virtual and override Modifiers
There are some significant differences here between Java and C#. Method overriding in C# involves two keywords borrowed from C++ with no equivalents in Java ?virtual and override. Take note of them carefully.
Like Java
Private methods in the superclass cannot be overridden in a subclass. If a subclass has a method of the same signature as a private method in the superclass, this is not considered to be a method override. You can invoke the superclass's method, which has been overwritten in the subclass, by using the C# keyword base ?this is similar to Java's super keyword. Here is an example.
1: using System;
2:
3: class Child:Parent{ // Child extends Parent
4: public static void Main(){
5: new Child().DoThis();
6: }
7: public override void DoThis(){
8: Console.WriteLine("DoThis of child");
9: base.DoThis();
10: }
11: }
12:
13: class Parent{
14: public virtual void DoThis(){
15: Console.WriteLine("DoThis of parent");
16: }
17: }
Output:
c:\expt>test
DoThis of child
DoThis of parent
Unlike Java
If you want to override a method in C#, you need to declare the method which is intended to be overridden using the virtual keyword in the superclass. You have to declare the overriding method with the override keyword in the subclass. In Java, You override a method like this:
1: // Child.java
2: public class Child extends Parent{
3: public static void main(String args[]){
4: new Child().doSomething();
5: }
6: void doSomething(){ // no special keyword
7: System.out.println("running Child's version");
8: }
9: }
10:
11: class Parent{
12: void doSomething(){ // no special keyword
13: System.out.println("running Parent's version");
14: }
15: }
Output:
c:\expt>java Child
running Child's version
If you want to override a method in C#, you must use the virtual and override keywords. A method in the superclass to be overridden must be declared as a virtual method. A method which is overriding a virtual method must be declared as an override method. A non-virtual method (methods are non-virtual by default) cannot be overridden. This is the correct way to do it using the virtual and override keywords in C#:
1: using System;
2: public class Child:Parent{
3: public static void Main(){
4: new Child().DoSomething();
5: }
6: public override void DoSomething(){
7: Console.WriteLine("running Child's version");
8: }
9: }
10:
11: public class Parent{
12: public virtual void DoSomething(){
13: Console.WriteLine("running Parent's version");
14: }
15: }
For Java, an overriding method can have weaker (less strict) accessibility than the overridden method. The following code compiles and works in Java.
1: // Child.java
2: public class Child extends Parent{
3: public static void main(String args[]){
4: new Child().doSomething();
5: }
6: public void doSomething(){
7: System.out.println("running Child's version");
8: }
9: }
10:
11: class Parent{
12: protected void doSomething(){
13: System.out.println("running Parent's version");
14: }
15: }
However, C# insists that the overriding method must have the same accessibility as the overridden method. Examine the following C# class and its corresponding compilation error.
1: using System;
2: public class Child:Parent{
3: public static void Main(){
4: Child c = new Child();
5: c.DoSomething();
6: }
7: public override void DoSomething(){
8: Console.WriteLine("running Child's version");
9: }
10: }
11:
12: public class Parent{
13: protected virtual void DoSomething(){
14: Console.WriteLine("running Parent's version");
15: }
16: }
Compilation error:
Source1.cs(7,24): error CS0507: 'Child.DoSomething()':
cannot change access modifiers when overriding
'protected' inherited member 'Parent.DoSomething()'
Additional notes on virtual methods
By default (if you do not declare a method with the virtual keyword), methods are non-virtual, and non-virtual methods cannot be overridden. Although a virtual method can be overridden, it doesn't have to be. It doesn't matter if a virtual method is not overridden in a subclass ?it will be inherited by the subclass and can be invoked normally just like other inherited non-virtual methods. A virtual method cannot be declared with the following keywords ?static, abstract, or override. - Abstract methods are implicitly virtual (they must be overridden in a subclass before they can of use), but you cannot declare a method using both the abstract and virtual modifiers (this results in a compilation error). Just declare an abstract method with the abstract modifier alone. - Although an overriding method cannot have the virtual modifier, a method declared with the override modifier is 'automatically virtual' (in a sense) and you can still override that method in a future subclass.
Virtual methods cannot be declared as private. If you come across the term 'most derived method', it refers to what the name implies. A virtual method can be overridden in a subclass, which in turn can be overridden by another subclass, and so forth. The most derived method is the 'latest overridden version' in the subclass lowest in the hierarchy which has this method implemented.
Method hiding versus method overriding
Try something like this in C# without the virtual and override keywords (which looks like method overriding in Java):
1: using System;
2: public class Child:Parent{
3: public static void Main(){
4: new Child().DoSomething();
5: }
6: public void DoSomething(){ // override not used
7: Console.WriteLine("running Child's version");
9: }
10:
11: public class Parent{
12: public void DoSomething(){ // virtual not used
13: Console.WriteLine("running Parent's version");
14: }
15: }
A compilation warning appears, but the assembly file is still created:
Test.cs(5,15): warning CS0108: The keyword new is required on 'Child.DoSomething()'
because it hides inherited member 'Parent.DoSomething()'
The resultant EXE runs as expected too:
c:\expt>test
running Child's version
It may seem that the DoSomething method has been successfully overridden in the subclass despite a warning message. Far from being a discrepancy between the C# standard and the behavior of the C# compiler, you are actually doing something called method hiding here, rather than method overriding (see section 7.11).
|