The outputs are:
Constructor in BaseClass
Constructor in DerivedClass
What happens if there is no default constructor in the base class, but perhaps a parameterized constructor like the following?
public class BaseClass {
//---constructor---
public BaseClass(int x) {
Console.WriteLine("Constructor in BaseClass");
}
}
In that case, the compiler will complain that BaseClass
does not contain a default constructor.
Remember that if a base class contains constructors, one of them must be a default constructor.
Calling Base Class Constructors
Suppose BaseClass
contains two constructors — one default and one parameterized:
public class BaseClass {
//---default constructor---
public BaseClass() {
Console.WriteLine("Default constructor in BaseClass");
}
//---parameterized constructor---
public BaseClass(int x) {
Console.WriteLine("Parameterized Constructor in BaseClass");
}
}
And DerivedClass
contains one default constructor:
public class DerivedClass : BaseClass {
//---default constructor---
public DerivedClass() {
Console.WriteLine("Constructor in DerivedClass");
}
}
When an instance of the DerivedClass
is created like this:
DerivedClass dc = new DerivedClass();
The default constructor in BaseClass
is first invoked followed by the DerivedClass
. However, you can choose which constructor you want to invoke in BaseClass
by using the base keyword in the default constructor in DerivedClass
, like this:
public class DerivedClass : BaseClass {
//---default constructor---
public DerivedClass(): base(4) {
Console.WriteLine("Constructor in DerivedClass");
}
}
In this example, when an instance of the DerivedClass
is created, the parameterized constructor in BaseClass
is invoked first (with the argument 4 passed in), followed by the default constructor in DerivedClass
. This is shown in the output:
DerivedClass dc = new DerivedClass();
//---prints out:---
//Parameterized Constructor in BaseClass
//Constructor in DerivedClass
Figure 6-7 shows that IntelliSense lists the overloaded constructors in BaseClass
.
Figure 6-7
When an interface inherits from a base interface, it inherits all the base interface's functions signatures (but no implementation).
Let's explore the concept of interface inheritance by using the hierarchy of various classes defined earlier in the chapter, starting from the root class Shape
, with the Circle
and Rectangle
classes inheriting from it (the Square class in turn inherits from the Rectangle
class), as Figure 6-8 shows.
Figure 6-8
One problem with this class hierarchy is that for the Circle
class, using the inherited length
property to represent the diameter is a bit awkward. Likewise, for the Square
class the width
property should not be visible because the length and width of a square are the same. Hence, these classes could be better rearranged.
As you recall from Chapter 5, you can use an interface to define the signature of a class's members. Likewise, you can use interfaces to define the hierarchy of a set of classes. If you do so, developers who implement this set of classes will have to follow the rules as defined in the interfaces.
You can use interfaces to redefine the existing classes, as shown in Figure 6-9.
Figure 6-9
Here, the IShape
interface contains two methods — Area()
and Perimeter()
:
public interface IShape {
//---methods---
double Perimeter();
double Area();
}
Remember, an interface simply defines the members in a class; it does not contain any implementation. Also, there is no modifier (like virtual
or abstract
) prefixing the function members here, so you need not worry about the implementation of the Perimeter()
and Area()
methods — they could be implemented by other derived classes.
The ICircle
interface inherits from the IShape
interface and defines an additional radius
property:
public interface ICircle : IShape {
//---property---
double radius { get; set; }
}
The ISquare
interface inherits from the IShape
interface and defines an additional length
property:
public interface ISquare : IShape {
//---property---
double length { get; set; }
}
The IRectangle
interface inherits from both the IShape
and ISquare
interfaces. In addition, it also defines a width
property:
public interface IRectangle : IShape, ISquare {
//---property---
double width { get; set; }
}
So what does the implementation of these interfaces look like? First, implement the ISquare
interface, like this:
public class Square : ISquare {
//---property---
public double length { get; set; }
//---methods---
public double Perimeter() {
return 4 * (this.length);
}
public double Area() {
return (Math.Pow(this.length, 2));
}
}
Here, you provide the implementation for the length property as well as the two methods — Perimeter()
and Area()
.
You not need to implement the IShape
class because you can't provide any meaningful implementation of the Area()
and Perimeter()
methods here.
Because the IRectangle
interface inherits from both the ISquare
and IShape
interfaces and the ISquare
interface has already been implemented (by the Square
class), you can simply inherit from the Square
class and implement the IRectangle
interface, like this:
public class Rectangle : Square, IRectangle {
//---property---
public double width { get; set; }
}
If you implement the IRectangle
interface directly (without inheriting from the Square
class, you need to provide the implementation of the length property as well as the methods Perimeter()
and Area()
.
Читать дальше