Implementation Inheritance


If you want to declare that a class derives from another class, use the following syntax:

 class MyDerivedClass : MyBaseClass { // functions and data members here } 
Note

This syntax is very similar to C++ and Java syntax. However, C++ programmers, who will be used to the concepts of public and private inheritance, should note that C# does not support private inheritance, hence the absence of a public or private qualifier on the base class name. Supporting private inheritance would have complicated the language for very little gain. In practice, private inheritance is used extremely rarely in C++ anyway.

If a class (or a struct) also derives from interfaces, the list of base class and interfaces is separated by commas:

 public class MyDerivedClass : MyBaseClass, IInterface1, IInterface2 { // etc. 

For a struct, the syntax is as follows:

 public struct MyDerivedStruct : IInterface1, IInterface2 { // etc. 

If you do not specify a base class in a class definition, the C# compiler will assume that System.Object is the base class. Hence, the following two pieces of code yield the same result:

 class MyClass : Object  // derives from System.Object { // etc. } 

and

 class MyClass   // derives from System.Object { // etc. } 

For the sake of simplicity, the second form is more common.

Because C# supports the object keyword, which serves as a pseudonym for the System.Object class, you can also write:

 class MyClass : object   // derives from System.Object { // etc. } 

If you want to reference the Object class, use the object keyword, which is recognized by intelligent editors such as Visual Studio .NET and thus facilitates editing your code.

Virtual Methods

By declaring a base class function as virtual, you allow the function to be overridden in any derived classes:

 class MyBaseClass { public virtual string VirtualMethod() { return "This method is virtual and defined in MyBaseClass"; } } 

It is also permitted to declare a property as virtual. For a virtual or overridden property, the syntax is the same as for a non-virtual property, with the exception of the keyword virtual, which is added to the definition. The syntax looks like this:

 public virtual string ForeName {    get { return fName;}    set { fName = value;} } private string foreName;

For simplicity, the following discussion focuses mainly on methods, but it applies equally well to properties.

The concepts behind virtual functions in C# are identical to standard OOP concepts. You can override a virtual function in a derived class, and when the method is called, the appropriate method for the type of object is invoked. In C#, functions are not virtual by default, but (aside from constructors) can be explicitly declared as virtual. This follows the C++ methodology: for performance reasons, functions are not virtual unless indicated. In Java, by contrast, all functions are virtual. C# differs from C++ syntax, however, because it requires you to declare when a derived class's function overrides another function, using the override keyword:

 class MyDerivedClass : MyBaseClass { public override string VirtualMethod() { return "This method is an override defined in MyDerivedClass"; } } 

This syntax for method overriding removes potential runtime bugs that can easily occur in C++, when a method signature in a derived class unintentionally differs slightly from the base version, resulting in the method failing to override the base version. In C# this is picked up as a compile-time error, because the compiler would see a function marked as override but no base method for it to override.

Neither member fields nor static functions can be declared as virtual. The concept simply wouldn't make sense for any class member other than an instance function member.

Hiding Methods

If a method with the same signature is declared in both base and derived classes, but the methods are not declared as virtual and override, respectively, then the derived class version is said to hide the base class version.

In most cases, you would want to override methods rather than hide them; by hiding them you risk calling the "wrong" method for a given class instance. However, as shown in the following example, C# syntax is designed to ensure that the developer is warned at compile time about this potential problem, thus making it safer to hide methods if that is your intention. This also has versioning benefits for developers of class libraries.

Suppose you have a class called HisBaseClass:

 class HisBaseClass { // various members } 

At some point in the future you write a derived class that adds some functionality to HisBaseClass. In particular, you add a method called MyGroovyMethod(), which is not present in the base class:

 class MyDerivedClass: HisBaseClass { public int MyGroovyMethod() { // some groovy implementation return 0; } } 

One year later, you decide to extend the functionality of the base class. By coincidence, you add a method that is also called MyGroovyMethod() and has the same name and signature as yours, but probably doesn't do the same thing. When you compile your code using the new version of the base class, you have a potential clash because your program won't know which method to call. It's all perfectly legal C#, but because your MyGroovyMethod() is not intended to be related in any way to the base class MyGroovyMethod(), the result of running this code does not yield the result you want. Fortunately, C# has been designed in such a way that it copes very well when conflicts of this type arise.

In these situations, C# generates a compilation warning. That reminds you to use the new keyword to declare that you intend to hide a method, like this:

 class MyDerivedClass : HisBaseClass { public new int MyGroovyMethod() { // some groovy implementation return 0; } } 

However, because your version of MyGroovyMethod() is not declared as new, the compiler will pick up on the fact that it's hiding a base class method without being instructed to do so and generate a warning (this applies whether or not you declared MyGroovyMethod() as virtual). If you want, you can rename your version of the method. This is the recommended course of action, because it will eliminate future confusion. However, if you decide not to rename your method for whatever reason (for example, you've published your software as a library for other companies, so you can't change the names of methods), all your existing client code will still run correctly, picking up your version of MyGroovyMethod(). That's because any existing code that accesses this method must be doing so through a reference to MyDerivedClass (or a further derived class).

Your existing code cannot access this method through a reference to HisBaseClass; it would generate a compilation error when compiled against the earlier version of HisBaseClass. The problem can only happen in client code you have yet to write. C# arranges things so that you get a warning that a potential problem might occur in future code — and you will need to pay attention to this warning, and take care not to attempt to call your version of MyGroovyMethod() through any reference to HisBaseClass in any future code you add. However, all your existing code will still work fine. It may be a subtle point, but it's quite an impressive example of how C# is able to cope with different versions of classes.

Calling Base Versions of Functions

C# has a special syntax for calling base versions of a method from a derived class: base.<MethodName>(). For example, if you want a method in a derived class to return 90 percent of the value returned by the base class method, you can use the following syntax:

 class CustomerAccount { public virtual decimal CalculatePrice() { // implementation return 0.0M; } } class GoldAccount : CustomerAccount { public override decimal CalculatePrice() { return base.CalculatePrice() * 0.9M; } }  

Java uses a similar syntax, with the exception that Java uses the keyword super rather than base. C++ has no similar keyword but instead requires specification of the class name (CustomerAccount:: CalculatePrice()). Any equivalent to base in C++ would have been ambiguous because C++ supports multiple inheritance.

Note that you can use the base.<MethodName>() syntax to call any method in the base class — you don't have to call it from inside an override of the same method.

Abstract Classes and Functions

C# allows both classes and functions to be declared as abstract. An abstract class cannot be instantiated, whereas an abstract function does not have an implementation, and must be overridden in any non- abstract derived class. Obviously, an abstract function is automatically virtual (although you don't need to supply the virtual keyword; doing so results in a syntax error). If any class contains any abstract functions, that class is also abstract and must be declared as such:

 abstract class Building { public abstract decimal CalculateHeatingCost();   // abstract method } 

C++ developers will notice some syntactical differences in C# here. C# does not support the =0 syntax to declare abstract functions. In C#, this syntax would be misleading because =<value> is allowed in member fields in class declarations to supply initial values:

 abstract class Building { private bool damaged = false;   // field public abstract decimal CalculateHeatingCost();   // abstract method } 



Professional C# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net