Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаба №1 / books / csharp_ebook.pdf
Скачиваний:
63
Добавлен:
03.03.2016
Размер:
3.69 Mб
Скачать

Programmers Heaven: C# School

a.MethodA();

But it is incorrect to write:

a.MethodB();

// error

 

 

Although we have an object of type B (contained in the reference of type A), we can not access any member of type B since the apparent type here is A and not B.

Using methods with the same name in the Base and the Sub-class

In our Shape class let us define a method Draw() that draws a shape on the screen:

class Shape

{

public void Draw()

{

Console.WriteLine("Drawing Shape...");

}

}

We inherit another class Circle from the Shape class, which also contains a method Draw().

class Circle : Shape

{

public void Draw()

{

Console.WriteLine("Drawing Circle...");

}

}

Here, we have the Draw() method with the same signature in both the Shape and the Circle classes. Now, if in our Main() method, we write

static void Main()

{

Circle theCircle = new Circle(); theCircle.Draw();

}

Circle's Draw() method is called and the program will (expectedly) display:

91

Programmers Heaven: C# School

Drawing Circle...

Note that the compiler will give a warning that Draw() in Circle hides the inherited Draw() method of Shape class. If in our Main() method we write

Shape theShape = new Circle();

theShape.Draw();

Shape's Draw() method is called and the program will display:

Drawing Shape...

Overriding the methods - virtual and override keywords

Now, if we want to override the Draw() method of the Shape class in the Circle class, we have to mark the Draw() method in the Shape (base) class as virtual and the Draw() method in the Circle (sub) class as override.

class Shape

{

public virtual void Draw()

{

Console.WriteLine("Drawing Shape...");

}

}

class Circle : Shape

{

public override void Draw()

{

Console.WriteLine("Drawing Circle...");

}

}

Now, in our Main() method we write

static void Main()

{

Shape theShape = new Circle(); theShape.Draw();

}

92

Programmers Heaven: C# School

Here we have used the reference of the base type (Shape) to refer to an object of the sub type (Circle) and call the Draw() method through it. As we have overridden the Draw() method of Shape in the Circle class and since the Draw() method is marked virtual in Shape, the compiler will no longer see the apparent (or reference) type to call the method (static, early or compile time object binding), rather, it will apply "dynamic, late or runtime object binding" and will see the object type at 'runtime' to decide which Draw() method it should call. This procedure is called polymorphism; where we have different implementations of a method with the same name and signature in the base and sub-classes. When such a method is called using a base-type reference, the compiler uses the actual object type referenced by the base type reference to decide which of the methods to call. When we compile the above program, the result will be:

Drawing Circle...

Although, we called the Draw() method using the reference of Shape type, the CLR will consider the object held by the Shape reference and calls the Draw() method of the Circle class.

We mark that method in the base class on which we want to achieve polymorphism as virtual. By marking a method virtual, we allow a method to be overridden and be used polymorphically. In the same way, we mark the method in the sub-class as override when it is overriding the virtual method in the base class. By marking the method as override, we announce that we are deliberately overriding the corresponding virtual method in the base class.

Author's Note: All the methods in C# are non-virtual by default unlike Java (where all the methods are implicitly virtual). We have to explicitly mark a method as virtual (like C++). Unlike C++ and Java, we also have to declare the overriding method in the sub-class as override in order to avoid any unconscious overriding. In fact, C# also introduces the new keyword to mark the method as non-overriding.

You might be wondering why in the previous example (of Shape and Circle class), late binding is necessary as the compiler can decide from the previous line which object the reference (theShape) holds.

Shape theShape = new Circle();

theShape.Draw();

Yes, it is possible for the compiler to conclude it in this particular case, but usually the compiler is not able to decide the object of which class the reference would be referencing at run-time.

Suppose we define two more classes: Rectangle and Curve which also inherit the Shape class and override its Draw() method to have their own specific implementations.

class Rectangle : Shape

{

public override void Draw()

{

93

Programmers Heaven: C# School

Console.WriteLine("Drawing Rectangle...");

}

}

class Curve : Shape

{

public override void Draw()

{

Console.WriteLine("Drawing Curve...");

}

}

Now, if we write the Main() method as follows:

static void Main()

{

Shape [] shapes = {new Circle(), new Rectangle(), new Curve()};

Random random = new Random();

for(int i=0; i<5; i++)

{

int randNum = random.Next(0, 3); shapes[randNum].Draw();

}

}

Here, we have made an array of type Shape and stored an object of the Circle, Rectangle and Curve classes in it. Next, we used the Random class to generate a random number between 0 and 2 (both 0 and 2 inclusive). We use this randomly generated number as an index in the shapes array to call the Draw() method. Now, neither we nor the compiler is sure which particular index of shapes will be used and the Draw() method of which sub-class of Shape would be called at runtime in each iteration of the loop. When we compile and run the above program, we will see a different output with each run. For example, when I execute the above program, I get the following output:

Drawing Curve...

Drawing Rectangle...

Drawing Curve...

Drawing Circle...

Drawing Rectangle...

Press any key to continue

94

Соседние файлы в папке books