Inheritance: © University of Linz, Institute For System Software, 2004 Published Under The Microsoft Curriculum License
Inheritance: © University of Linz, Institute For System Software, 2004 Published Under The Microsoft Curriculum License
2
Assignments and Type Checks
A
class A {...}
class B : A {...} B
class C: B {...}
C
Assignments
A a = new A(); // static type of a: the type specified in the declaration (here A)
// dynamic type of a: the type of the object in a (here also A)
a = new B(); // dynamic type of a is B
a = new C(); // dynamic type of a is C
a = new C();
if (a is C) ... // true, if the dynamic type of a is C or a subclass; otherwise false
if (a is B) ... // true
if (a is A) ... // true, but warning because it makes no sense
a = null;
if (a is C) ... // false: if a == null, a is T always returns false
3
Checked Type Casts
Cast
A a = new C();
B b = (B) a; // if (a is B) static type(a) is B in this expression; else exception
C c = (C) a;
a = null;
c = (C) a; // ok null can be casted to any reference type
as
A a = new C();
B b = a as B; // if (a is B) b = (B)a; else b = null;
C c = a as C;
a = null;
c = a as C; // c == null
4
Overriding Methods
Only methods that are declared as virtual can be overridden in subclasses
class A {
public void F() {...} // cannot be overridden
public virtual void G() {...} // can be overridden in a subclass
}
class B : A {
public void F() {...} // warning: hides inherited F() use new
public void G() {...} // warning: hides inherited G() use new
public override void G() { // ok: overrides inherited G
... base.G(); // calls inherited G()
}
}
class B : A {
public override void WhoAreYou() { Console.WriteLine("I am a B"); }
}
A message invokes the method belonging to the dynamic type of the receiver
(not quite true, see later)
A a = new B();
a.WhoAreYou(); // "I am a B"
Benefit: every method that can work with A can also work with B
void Use (A x) {
x.WhoAreYou();
}
6
Hiding
Members can be declared as new in a subclass.
They hide inherited members with the same name and signature.
class A {
public int x;
public void F() {...}
public virtual void G() {...}
}
class B : A {
public new int x;
public new void F() {...}
public new void G() {...}
}
B b = new B();
b.x = ...; // accesses B.x
b.F(); ... b.G(); // calls B.F and B.G
7
Dynamic Binding (with Hiding)
Method resolution for obj.M() A
st = static type of obj; virtual void M()
dt = dynamic type of obj;
m = Method "M" of st; B
for (all types t between st (exclusive) and dt (inclusive)) {
if (t has an overriding method "M") m = "M" of t; override void M()
else if (t has a non-overriding method "M") break;
} C
call m; new void M()
A obj = new C();
Works as expected for simple cases obj.M();
class Animal {
public virtual void WhoAreYou() { Console.WriteLine("I am an animal"); }
}
class Dog : Animal {
public override void WhoAreYou() { Console.WriteLine("I am a dog"); }
}
9
Fragile Base Class Problem
Initial situation
class LibraryClass {
public void CleanUp() { ... }
}
class MyClass : LibraryClass {
public void Delete() { ... erase the hard disk ... }
}
class LibraryClass {
string name;
public virtual void Delete() { name = null; ... }
public void CleanUp() { Delete(); ... }
}
class MyClass : LibraryClass { In Java the call myObj.CleanUp()
public void Delete() { ... erase the hard disk ... }
}
would erase the hard disk!
OK OK Error! OK
- Default constr. A() - A() - no explicit call of - A(int x)
- B(int x) - B(int x) the A() constructor - B(int x)
- default constr. A()
does not exist
11
Visibility protected and internal
protected Visible in the declaring class and its subclasses
(more restricive than in Java)
internal Visible in the declaring assembly (see later)
protected internal Visible in declaring class, its subclasses and the declaring assembly
Example
class Stack {
protected int[] values = new int[32];
protected int top = -1;
public void Push(int x) {...}
public int Pop() {...}
}
class BetterStack : Stack {
public bool Contains(int x) {
foreach (int y in values) if (x == y) return true;
return false;
}
}
class Client {
Stack s = new Stack();
... s.values[0] ... // illegal: compilation error
} 12
Abstract Classes
Example
Note
13
Abstract Properties and Indexers
Example
Note
• Overridden indexers and properties must have the same get and set methods as in the
base class
14
Sealed Classes
Example
Note
15
Class System.Object
Topmost base class of all other classes
class Object {
protected object MemberwiseClone() {...}
public Type GetType() {...}
public virtual bool Equals (object o) {...}
public virtual string ToString() {...}
public virtual int GetHashCode() {...}
}
Directly usable:
Overridable in subclasses:
class Client {
static void Main() {
Fraction a = new Fraction(1, 2);
Fraction b = new Fraction(1, 2);
Fraction c = new Fraction(3, 4);
Console.WriteLine(a.ToString()); // 1/2
Console.WriteLine(a); // 1/2 (ToString is called automatically)
Console.WriteLine(a.Equals(b)); // true
Console.WriteLine(a == b); // false
Console.WriteLine(a.GetHashCode()); // 3
a = c.ShallowCopy(); 17
Console.WriteLine(a); // 3/4
Example (for overloading == and !=)
class Fraction {
int x, y;
public Fraction(int x, int y) { this.x = x; this.y = y; }
...
public static bool operator == (Fraction a, Fraction b) { return a.x == b.x && a.y == b.y; }
public static bool operator != (Fraction a, Fraction b) { return ! (a == b); }
}
class Client {
static void Main() {
Fraction a = new Fraction(1, 2);
Fraction b = new Fraction(1, 2);
Fraction c = new Fraction(3, 4);