560 likes | 686 Views
Set# 3 Advanced Concepts . Inheritance:. Protected access modifier. Virtual Methods and Overriding. class Employee { public void CalculatePay() { Console.WriteLine("Employee.CalculatePay()"); } } class SalariedEmployee : Employee { new public void CalculatePay() { // public new …..
E N D
Set# 3 Advanced Concepts Inheritance:
Virtual Methods and Overriding class Employee { public void CalculatePay() { Console.WriteLine("Employee.CalculatePay()"); } } class SalariedEmployee : Employee { new public void CalculatePay() { // public new ….. Console.WriteLine("SalariedEmployee.CalculatePay()"); } } class TestNewMethods { static void Main(string[ ] args) { Employee e = new Employee(); e.CalculatePay(); SalariedEmployee s = new SalariedEmployee(); s.CalculatePay(); } } This code work as expected, BUT???
Virtual Methods and Overriding what happen if upcasting is done?? – Employee em=new SalariedEmployee(); – em. CalculatePay() ; //which one will be called. Answer: it will call the employee to calculate function (CalculatePay()). 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. The result is that which version of a method gets called depends on the type of the variable used to reference the instance, not the type of the instance itself.
Example, with upcasting using System; class Employee { public void CalculatePay() { Console.WriteLine("Employee.CalculatePay()"); } } class SalariedEmployee : Employee { new public void CalculatePay() { Console.WriteLine("SalariedEmployee.CalculatePay()"); } } class TestNewMethods { static void Main(string[ ] args) { Employee e = new SalariedEmployee();// upcasting e.CalculatePay(); SalariedEmployee s = new SalariedEmployee(); s.CalculatePay(); } }
Polymorphism (overriding) • To solve the previous problem, use the two keywords: virtual and override. – use the virtual keyword on the base class’s method. – use the override keyword on the derived class’s implementation of that method. • Note that an override function must have the same access level (protected, public, and so on) as the virtual function it overrides. • Also, a virtual membercan’t be declared private because the member would then be impossible to override.
Example using System; class Employee{ public string name; public Employee(string name){ this.name = name; } public virtual void CalculatePay(){ Console.WriteLine("Employee.CalculatePay called for {0}", name); } } class ContractEmployee : Employee{ public ContractEmployee(string name) : base(name){ } public override void CalculatePay(){ Console.WriteLine("ContractEmployee.CalculatePay called for {0}", name); } }
class SalariedEmployee : Employee { public SalariedEmployee (string name) : base(name) { } public override void CalculatePay() { Console.WriteLine("SalariedEmployee.CalculatePay called for {0}",name); } } class TestPolymorphic { protected Employee[] employees; public void LoadEmployees() { employees = new Employee[2]; employees[0] = new ContractEmployee("Adam "); // upcasting employees[1] = new SalariedEmployee("ahmad");// upcasting } public void DoPayroll(){ for (int i = 0; i < employees.GetLength(0); i++){ employees[i].CalculatePay(); } }
Example, cont… static void Main(string[] args){ TestPolymorphic t = new TestPolymorphic(); t.LoadEmployees(); t.DoPayroll(); } }
Another version of TestPolymorphic class TestPolymorphic { static void Main(string[] args) { Employee[] employees; employees = new Employee[2]; employees[0] = new ContractEmployee("Adam "); // upcasting employees[1] = new SalariedEmployee("ahmad");// upcasting foreach (Employee e in employees) e.CalculatePay(); } }
Abstract Class • Motivation: if you think no object of a class should be created, declare the class abstract • In general, an abstract class is a placeholder in a class hierarchy that represents a generic concept • The use of abstract classes is a design decision; it helps us establish common elements in a class that is too general to instantiate Vehicle Car Boat Plane
Abstract Classes: Syntax • Use the modifier abstract on a class header to declare an abstract class, e.g.,abstract class Vehicle{ // … public abstract void Move();}class Car : Vehicle{ //… public void Move() { Console.WriteLine( “Car is moving!” ); }}abstract class StaffMember{ // … public abstract double Pay();}
Abstract class The child of an abstract class must override the abstract methods of the parent, or it too must be declared abstract Only abstract classes can contain abstract methods An abstract class cannot be instantiated
Sealed Classes C# allows classes and methods to be declared as sealed. In the case of a class, this means that you can’t inherit from that class. In the case of a method, this means that you can’t override that method.
Parameters similar to ref parameters but no value is passed by the caller.
out Parameter using System; class Test { void Read(out int first, out int next){ first = Console.Read(); // read '0' as character converted to Decimal = 48 next = Console.Read(); } void f(){ int first, next; Read(out first, out next); Console.WriteLine(first); // 48 Console.WriteLine(next);// 48 } public static void Main() { Test t = new Test(); t.f(); // f() is non static and main is static so we need an object of class to access } }
Parameter passing Summary Two types of parameter passing: - Call by value: a modification on the formal argument has no effect on the actual argument - Call by reference: a modification on the formal argument can change the actual argument Depend on the type of a formal argument For C# simple data types, it is call-by-value Change to call-by-reference: ref or out The ref or out keyword is required in both method declaration and method call ref requires that the parameter be initialized before enter a method out requires that the parameter be set before return from a method
Variable Number of Parameters void Add(out int sum, params ref int[] val) // Error
Example class Test{ void Add(out int sum, params int[] val) { sum = 0; foreach (int i in val) sum = sum + i; } static void Main() { Test v = new Test(); int sum; v.Add(out sum, 3, 5, 2, 9); // sum == 19 Console.WriteLine(sum); } }
Example 2 using System; class Test{ void Add(out string sum, params string[] val){ sum = “"; foreach (string i in val) sum = sum +" "+ i; } static void Main() { Test v = new Test(); string sum; v.Add(out sum, "This", "is","Just","an example"); // This is Just an example Console.WriteLine(sum); } }
Class Constructors Example: using system; class Constructor1App { Constructor1App() { Console.WriteLine("I'm the constructor"); } public static void Main() { Console.WriteLine(" Constructor1 object..."); Constructor1App app = new Constructor1App(); } } • Purpose: initialize objects of the class • They have the same name as the class • There may be more then one constructor per class (overloaded constructors) • can take arguments • they do not return any value • it has no return type, not even void
Constructors for Classes • this(…) Enables the current class to call another constructor defined within itself.
Constructor Initializers • base(…) Enables you to call the current class’s base class constructor. • this(…) Enables the current class to call another constructor defined within itself. This is useful when you have overloaded multiple constructors and want to make sure that a default constructor is always called.
Example class MyBase{ protected MyBase(int i) { } }; class MyDerived : MyBase{ int i; MyDerived(int i) : base(i) { } // call the constructor of base class };
Example 2 using System; class BaseClass{ public BaseClass() { Console.WriteLine("Parameterless constructor called"); } public BaseClass(int foo) { Console.WriteLine("foo = {0}", foo); } } class DerivedClass : BaseClass{ public DerivedClass(int foo): base(foo){ Console.WriteLine("foo = {0}", foo); } } class BaseInitializer3{ public static void Main(){ Console.WriteLine("Main: DerivedClass object..."); DerivedClass derived = new DerivedClass(42); } }
Example 3 using System; class CommaDelimitedFile{ public CommaDelimitedFile(string fileName) { Console.WriteLine("file name = {0}", fileName); } } enum TableId{ Customers,Suppliers, Vendors }; class DbTable : CommaDelimitedFile { public DbTable(TableId tableId): base(GetFileName(tableId)){ Console.WriteLine("tableId = {0}", tableId.ToString()); }
Example, cont.. static string GetFileName(TableId tableId) { string fileName; switch(tableId) { case TableId.Customers: fileName = "customers.txt"; break; case TableId.Suppliers: fileName = "suppliers.txt"; break; case TableId.Vendors: fileName = "venders.txt"; break; default: throw new ArgumentException("Could not resolve table nam"); } return fileName; } } class BaseInitializer4{ public static void Main(){ Console.WriteLine("Customer Table object..."); DbTable derived = newDbTable(TableId.Customers); } }
Destructors Is a method that’s called when an object is destroyed or goes out of scope. • Each class has only at most one destructor (also called finalizer) • Name of a destructor is the ~ character, followed by the class name • Destructors do not receive any arguments
Overriding Inherited Properties using System; class CFile { public CFile(string fileName) { this.fileName = fileName; } protected string fileName; public virtual string FileName{ get { return fileName; } } } class CustomerTable : CFile{ public const string FILENAME = "customers.txt"; public CustomerTable() : base(FILENAME) { } public override string FileName{ get { return "Customers table"; } } }
Overriding Inherited Properties, cont.. class OverrideProperties{ public static void Main() { CFilecustomerFile = new CFile(CustomerTable.FILENAME); Console.WriteLine("Customer file name = {0}", customerFile.FileName); CustomerTablecustomerTable = new CustomerTable(); Console.WriteLine("Customer file name = {0}", customerTable.FileName); } }
Using Interface for Multiple Inheritance • Java/C# decision: single inheritance, meaning that a derived class can have only one parent class • To take the advantages of multiple inheritance, Java/C# defines interfaces, which give us the best aspects of multiple inheritance without the complexity
C# Interface • A C# interface is a collection of methods, and properties • it can actually include other types of definitions • These methods and properties have no implementation • An interface is used to formally define a set of methods that a class will implement • An interface captures one aspect of a class • If class D is derived from class B, then you should feel comfortable in saying an object of D is also a B • If class D implements interface I, then you should feel comfortable in saying an object of D has I perspective
Interfaces: Syntax interface is a reserved word public interface IComplexity { int Level { get; set; } } public interface IDisplayAble{ void Paint(); } // inherits Question, implements two interfaces class MultiChoice: Question, IComplexity, IDisplayAble { public void Paint() {...} public int Level {...} public string GetQuestionPart() {} public string GetAnswerPart() {}}
Interfaces • Methods in an interface have public visibility by default • An interface cannot be instantiated • A class implements an interface by • stating so in the class header after : • A class can implement multiple interfaces: the interfaces are separated by commas • If a class asserts that it implements an interface, it must define all methods in the interface or the compiler will produce errors • A class that implements an interface can implement other methods as well
Polymorphism via Interfaces • An interface name can be used as the type of an object reference variable IDoableobj; • The obj reference can be used to point to any object of any class that implements the IDoable interface • The version of doThis that the following line invokes depends on the type of object that obj is referring to: obj.doThis();
public interface ISpeak { public void Speak(); } class Faculty {…} class Professor: Faculty, ISpeak { // public void Speak(){…} public void Pontificate() {…} } class Animal {} class Dog: Animal, ISpeak { // public void Speak(){ … } } ISpeak guest; guest = new Professor(); guest.Speak(); guest = Dog(); guest.Speak(); An Example ISpeak special; special = new Professor(); special.Pontificate(); // compiler error ISpeak special; special = new Professor(); ((Professor)special).Pontificate();
Interfaces • Includes method declarations only. • It can contain methods, properties, indexers (next slide) none of which are implemented in the interface itself. • Interfaces, by definition, are abstract classes. • You don’t need to specify an access modifier such as public on an interface method. • Any class that implements an interface must define each and every member of that interface •Interfaces can extend other interfaces.
Example interface ex { // Example method declaration bool Validate(); // Example read-only property declaration inttestProperty { get; } // Example indexer declaration string this[int index] { get; set; } } Indexer is sometimes referred to as a smart array, that is, a member that enables you to work with a class that’s logically an array of data. (Detailed discussion Later)
example using System; public interface IDataBound{ void Bind(); } public class EditBox : IDataBound{ // implements interface // IDataBound implementation public void Bind() { Console.WriteLine("Binding to data store..."); } } class NameHiding1App{ // Main entry point public static void Main(){ Console.WriteLine(); EditBox edit = new EditBox(); Console.WriteLine("Calling EditBox.Bind()..."); edit.Bind(); Console.WriteLine(); IDataBound bound = (IDataBound)edit; // object of interface Console.WriteLine("Calling (IDataBound)" + "EditBox.Bind()..."); bound.Bind(); } } // see interfaceEx
Avoiding Name Ambiguity – Explicitinterface implementation. using System; interfaceISerializable{ void SaveData();} interfaceIDataStore { void SaveData(); } class Test : ISerializable, IDataStore { void IDataStore.SaveData() { Console.WriteLine("[Test.SaveData] IDataStore "+ "implementation called"); } void ISerializable.SaveData() { Console.WriteLine("[Test.SaveData] ISerializable“ + "implementation called");} static void Main(){ Test t = new Test(); ISerializable a = (ISerializable)t; a.SaveData(); IDataStore b = (IDataStore)t; b.SaveData(); } }// see explicit
Indexers class MyClass { public objectthis [int index] { get { // Return desired data. } set { // Set desired data. } } } • To use it: MyClasscls = new MyClass(); cls[0] = someObject; Console.WriteLine("{0}", cls[0]); Note: Indexers enable a class’s client to index into an object as though the object itself were an array.
Indexer , example using System; class IntIndexer{ private string[] myData; public IntIndexer(int size) { myData = new string[size]; for (int i=0; i < size; i++){ myData[i] = "empty"; } } public stringthis[int pos] { get{ return myData[pos]; } set { myData[pos] = value; } } static void Main(string[] args) { int size = 10; IntIndexer myInd = new IntIndexer(size); myInd[9] = "Some Value"; // invoke set myInd[3] = "Another Value"; myInd[5] = "Any Value"; Console.WriteLine("\nIndexer Output\n"); for (int i=0; i < size; i++) { Console.WriteLine("myInd[{0}]: {1}", i,myInd[i]); } } }
overloaded indexers using System; class OvrIndexer{ private string[] myData; private int arrSize; public OvrIndexer(int size) { arrSize = size; myData = new string[size]; for (int i=0; i < size; i++){ myData[i] = "empty"; } } public stringthis[int pos] { get { return myData[pos]; } set{ myData[pos] = value; } } public stringthis[string data]{ get{ int count = 0; for (int i=0; i < arrSize; i++){ if (myData[i] == data){ count++;} } return count.ToString(); } set{ for (int i=0; i < arrSize; i++){ if (myData[i] == data){ myData[i] = value; } } } }
overloaded indexers static void Main(string[] args){ int size = 10; OvrIndexer myInd = new OvrIndexer(size); myInd[9] = "Some Value";// invoke set myInd[3] = "Another Value"; myInd[5] = "Any Value"; myInd["empty"] = "no value"; // invoke set Console.WriteLine("\nIndexer Output\n"); for (int i=0; i < size; i++) { Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]); // invoke get } Console.WriteLine("\nNumber of \"no value\" entries: {0}", myInd["no value"]); // invoke get } }
using System; class MonthlySales { int[] product1 = new int[12]; int[] product2 = new int[12]; public int this[int i] {// set method omitted => read-only get { return product1[i-1] + product2[i-1]; } } public int this[string month] { // overloaded read-only indexer get { switch (month) { case "Jan": return (product1[0] + product2[0]); case "Feb": return (product1[1] + product2[1]); default: return 1; } } } static void Main(string[] args){ MonthlySales sales = new MonthlySales(); Console.WriteLine(sales[1]+ sales["Feb"]); } } overloaded indexers.