Professional Documents
Culture Documents
This chapter explains function overloading, the params parameter and inheritance. We start with
function overloading.
Function Overloading
a.cs
class zzz
a.abc(10);
a.abc("bye");
a.abc("no",100);
class yyy
System.Console.WriteLine("abc" + i);
System.Console.WriteLine("abc" + i);
System.Console.WriteLine("abc" + i + j);
Output
abc10
abcbye
abcno100
The class yyy has three functions, all of them having the same name abc. The distinction
between them is in the data types of the parameters. They are all different. In C# we are allowed
to have functions with the same name, but having different data types parameters. The advantage
is that we call the function by the same name as by passing different parameters, a different
function gets called. This feature is called function overloading. All is fine only if the parameter
types to the function are different. We do not have to remember a large number of functions by
name.
The only reason why function overloading works is that C# does not know a function by name,
but by its signature. A signature denotes the full name of the function. Thus the name of a
function or its signature is the original function name plus the number and data types of its
individual parameters.
a.cs
class zzz
Compiler Error
a.cs(6,12): error CS0111: Class 'zzz' already defines a member called 'abc' with the same
parameter types
Here we have two functions abc which differ only in the values they return. As return values do
not count in the function signature and the function names are similar, hence the error.
a.cs
class zzz
Compiler error
a.cs(6,14): error CS0111: Class 'zzz' already defines a member called 'abc' with the same
parameter types
We have 2 abc's, that accept an int and differ only in the addition of a modifier static. They have
the same signature as modifiers like static are not considered as part of the function signature.
Also, in the next program, we have two abc's with different access modifiers which differ in the
parameters, hence signature/name changes causing an error.
a.cs
class zzz
void abc(int i)
i = 10;
}
Compiler Error
a.cs(10,6): error CS0663: 'abc' cannot define overloaded methods which differ only on ref and
out
The signature consists of not only the parameter data types, but also the kind of parameters i.e.
out ref etc. As function abc takes an int with different modifiers i.e. out etc, the signature on each
is different. The signature of a method consists of its name and number and types of its formal
parameters. The return type of a function is not part of the signature. No two functions can have
the same signature and also non-members cannot have the same name as members.
A function/method can be called by four different types of parameters. These are pass by value,
reference, output and finally parameter arrays. The parameter modifier is not part of the function
signature. Lets now understand what parameter arrays are all about.
Params Parameter
A method declaration creates a separate declaration space. This means that anything created in a
method is lost at the end of the method.
a.cs
string i;
Compiler Error
a.cs(6,8): error CS0136: A local variable named 'i' cannot be declared in this scope because it
would give a different meaning to 'i', which is already used in a 'parent or current' scope to
denote something else
Parameter names have to be unique. Also, we cannot have a parameter and a variable created in a
function block with the same name.
In pass by value, the value of the variable is passed. In the case of ref and out, the address of the
reference is passed.
a.cs
string s = "hi";
{
zzz z = new zzz();
z.pqr();
void pqr()
System.Console.WriteLine(s);
System.Console.WriteLine(s);
a="no";
System.Console.WriteLine(s);
b = "yes";
System.Console.WriteLine(s);
s = "maybe";
Output
hi
no
yes
maybe
You are allowed to pass the same ref parameter as many times as you desire. In the function abc
the string s has a value of hi. Then by changing the string b to no, we are actually changing the
string s to no as s is passed by reference. Variables a and s refer to the same string in memory.
Changing one changes the other. Again changing b also changes s as they refer to the same
string. Thus variables a, b and s refer to the same string in memory.
a.cs
z.pqr();
void pqr()
abc(2,"hi","bye","no");
abc(20,"hi");
abc(2);
foreach ( string s in b)
Output
hi 2
bye 2
no 2
hi 20
We will encounter a situation where we would like to pass a variable number of arguments to a
function. This is not possible as of now as C# is extremely finicky about the number and type of
data we pass to a function. If we pass a string where an int is expected, C# starts screaming like a
baby. If we want to pass a variable number of arguments to a function, we have to use a keyword
params. This keyword can only be applied to the last parameter. Therefore the variable number
of arguments can only come at the end. In the case of function abc, the first parameter has to be
an int, the rest of them can be from zero to an infinite number of strings.
a.cs
Compiler Error
a.cs(6,18): error CS0231: A params or __arglist parameter must be the last parameter in a formal
parameter list
The params keyword in this version has to be at the end only as stated above.
a.cs
z.pqr();
void pqr()
abc(2,3,4);
abc(20,1);
abc(2);
foreach ( int s in b)
Output
32
42
1 20
C# is smart enough if the penultimate parameter and the params have the same data type. The
first int is stored in the variable i, the rest are made part of the array b.
a.cs
Compiler Error
a.cs(6,6): error CS0225: The params parameter must be a single dimensional array
The data type of the params parameter must be, as the error message states, a single dimensional
array. Thus [][] is allowed but not [,]. You are also not allowed to combine the params keyword
with ref or out.
a.cs
z.pqr();
void pqr()
string [] s = {"hi","bye","no"};
abc(2,s);
foreach ( string s in b)
Output
hi 2
bye 2
no 2
You are allowed to pass an array of strings instead of individual strings as parameters. Here s is
an array of strings which has been initialized using the short form. Internally when we call the
function abc, C# converts the array of strings into individual strings.
a.cs
z.pqr();
void pqr()
{
string [] s1 = {"hi","bye"};
abc(2,s1,"hell");
Compiler Error
a.cs(11,1): error CS1502: The best overloaded method match for 'zzz.abc(int, params string[])'
has some invalid arguments
a.cs(11,7): error CS1503: Argument '2': cannot convert from 'string[]' to 'string'
Mixing and matching is not allowed in C#. What we assumed C# would do is to add the last
string hell to the array of strings s1 or convert s1 to individual strings and then add the string hell
to it. Perfectly logical we thought. Only if wishes were horses…
Internally before calling the function abc, it collects all the individual parameters and converts it
into one big array for the params statement.
a.cs
z.pqr();
}
void pqr()
int [] a = {1,2,3};
abc(2,a);
System.Console.WriteLine(a[1]);
b[1] = 100;
Output
100
The output produced is proof of concept. The array member a[1] has an initial value of 2 and in
the function abc we change it to 100. The original changes, this means that the array is given to
the function abc.
a.cs
z.pqr();
}
void pqr()
int a = 10;
abc(2,100,a,20);
System.Console.WriteLine(a);
b[1] = 100;
Output
10
In this case C# creates an array containing 100 10 and 20. We are changing the second member
to 100 which has nothing to do with the variable a. As abc has no knowledge of a, how on earth
can abc change the value of the int a? Thus it stays the same.
a.cs
z.pqr();
}
void pqr()
abc(2);
abc(2,3);
abc(2,3,5,6);
System.Console.WriteLine("params a");
Output
params a
two ints 2 3
params a
Here we are discussing function overloading. C# is extremely bright though partial. It does not
like the params statement and treats it like a stepchild. When we call abc with one int, C# can
only call the abc that takes a params as a parameter as it matches one int. An array can contain
one member. The fun starts with the abc that is being called with two ints. Here we have a
dilemma. C# can call the params abc or the abc with two ints. As mentioned earlier, C# treats the
params as a second class citizen and therefore chooses the abc with two ints. When there are
more than two ints like in the third invocation, C# has no choice but to grudgingly choose the
abc with the params. C# chooses the params as a last resort before flagging an error.
a.cs
using System;
class zzz
foreach (object o in b) {
Console.WriteLine();
object o = a;
ff(a);
ff((object)a);
ff(o);
ff((object[])o);
Output
System.Object[]
System.Object[]
System.Int32 System.String System.Double
In the first case we are passing the function ff an array of object that looks like object. We will
tell you a little later that all classes are derived from object. The function ff receives an array of
objects b. In the foreach we know that the object class has a function GetType that returns an
object that looks like Type, which in turn has a function called FullName which returns the name
of the type. We see three different types displayed. In the second invocation of ff we are casting
a to an object. There is no conversion available from converting an object to an object array i.e.
object []. Therefore a one element object [] is created. It's the same case in the third invocation
and the last explicitly casts to an object array.
a.cs
using System;
class zzz
Console.WriteLine(b.GetType().FullName);
Console.WriteLine(b.Length);
Console.WriteLine(b[0]);
ff((object)a);
Output
System.Object[]
System.Object[]
Inheritance
a.cs
class zzz
a.abc();
class yyy
System.Console.WriteLine("yyy abc");
System.Console.WriteLine("yyy pqr");
class xxx
{
Compiler Error
a.cs(6,1): error CS0117: 'xxx' does not contain a definition for 'abc'
The class yyy contains 2 functions and one instance variable. The class xxx contains no code and
no variables at all. An empty class does not denote any error as we are able to instantiate an
object that looks like xxx. The error comes about because the class xxx has no function called
abc. However the class yyy has a function abc. Would it not be great if we were allowed to use
all the code in the class yyy from xxx. Easier said than done, we guess!
a.cs
class zzz
a.abc();
class yyy
System.Console.WriteLine("yyy abc");
}
public void pqr()
System.Console.WriteLine("yyy pqr");
Output
yyy abc
The error disappears and the abc in yyy gets executed. If after the name of the class you write :
yyy i.e. the name of another class, a lot happens at once. xxx is now said to have been derived
from yyy. What that means is all the code we wrote in yyy can now be used in xxx. It is if we
actually wrote all the code that is contained in yyy in xxx. If we had created an object that looks
like yyy, everything that the object could do, now an object that looks like xxx can also do. But
we have not written a line of code in xxx. We are made to believe that xxx has one variable i
and two functions abc and pqr as yyy contains these two functions. Here we are teaching you the
concepts of inheritance where yyy will now be called the base class, xxx the derived class.
a.cs
class zzz
a.abc();
}
class yyy
System.Console.WriteLine("yyy abc");
System.Console.WriteLine("yyy pqr");
System.Console.WriteLine("xxx abc");
Compiler Warning
a.cs(23,13): warning CS0108: The keyword new is required on 'xxx.abc()' because it hides
inherited member 'yyy.abc()'
Output
xxx abc
Nothing in the world stops class xxx from creating a function abc i.e. one with the same name as
in the base class . C# simply gives us a warning. When we run a.abc(), C# first checks whether
the class xxx (as a looks like xxx) has a function called abc. If it does not, then it will check in
the base class. Earlier abc was only available in the base class and hence got executed. Here as it
is already there in xxx, it gets called from xxx and not yyy. Remember the derived classes get a
first shot at execution, then the base class. The reason being, the base class may have a number
of functions and for various reasons you may not be satisfied with what they do. You should
have the right to have your copy of the function to be called. In other words the derived classes
functions override the ones in the base class.
a.cs
class zzz
a.abc();
class yyy
System.Console.WriteLine("yyy abc");
{
System.Console.WriteLine("yyy pqr");
System.Console.WriteLine("xxx abc");
base.abc();
Output
xxx abc
yyy abc
What if you want the best of both worlds? You may want to call the base classes abc first and
then yours or vice versa. To accomplish this, C# gives you a reserved word, something free
called base. The word base can be used in any derived class. It means call the function off the
base class. Simple. Thus base.abc will call the function abc from yyy the base class of xxx.
a.cs
class zzz
a.abc();
}
class yyy
System.Console.WriteLine("yyy abc");
System.Console.WriteLine("yyy pqr");
System.Console.WriteLine("xxx abc");
base.pqr();
Output
xxx abc
yyy pqr
There is only one small change made to the program and that is base.abc is replaced by base.pqr.
In this case the function pqr from the class yyy gets called. Base is very general purpose. It lets
you access members of the base class from the derived class. You cannot use base in yyy as yyy
is not derived from any class. Thus base can only be used in derived classes.
a.cs
class zzz
a.xyz();
class yyy
System.Console.WriteLine("yyy abc");
Compiler Error
a.cs(6,1): error CS0117: 'yyy' does not contain a definition for 'xyz'
In this case, xxx is derived from yyy and not vice versa. Thus xxx can use all the members of
yyy. Inheritance does not work backwards. Whatever members xxx comprises do not permeate
upwards to yyy. Class xxx may now have a function xyz but it cannot give it to class yyy and
thus an error occurs.
A class inherits everything from its base class except the constructors and destructors. If a class c
is derived from class b, which in turn has been derived from class a, class c inherits all the
members declared in class b and also class a. This concept is called transitive. A derived class
can inherit all the members of the base class but cannot subtract or remove members off that base
class. A derived class can hide members of the base class by creating functions by the same
name. The original member in the base class remains unchanged and unaffected by whatever is
happening in the derived class. It remains unchanged in the base class, it is simply not visible in
the derived class.
A class member can either be a static member belonging to the class or an instance member
belonging to the instance i.e. accessible through the object and not the class. The default is non-
static.
A class is also called a data structure. It consists of data members like constants, fields and
events and function members like methods, properties, indexers, operators, constructors, static
constructors and destructors. A class within a class is called a nested class. Thus we can place 11
different types of entities in a class. Function members are the only members of a class that
contain executable code. A class creation creates a new declaration space.
All classes derive from object . Object is the mother of all classes.
a.cs
{
}
If you do not derive from any class, then the C# compiler automatically adds :object to your class
definition. Object, the only class to have this feature is not derived from any class. It is the
ultimate base class of all classes in the C# hierarchy.
class aa
class bb : aa
Class aa is the base class of bb . The documentation however calls aa the direct base class of bb.
Thus the base classes of bb are aa and object.
a.cs
class aa : System.Delegate
class bb : System.Enum
{
}
class cc : System.Array
class dd : System.ValueType
Compiler Error
a.cs(7,7): error CS0644: 'aa' cannot inherit from special class 'System.Delegate'
a.cs(10,7): error CS0644: 'bb' cannot inherit from special class 'System.Enum'
a.cs(13,7): error CS0644: 'cc' cannot inherit from special class 'System.Array'
a.cs(16,7): error CS0644: 'dd' cannot inherit from special class 'System.ValueType'
You cannot derive a class from the above 4 classes as they are special.
a.cs
class aa
}
class bb
class cc : aa, bb
Compiler Error
A class can only be derived from one more class . You are not permitted to derive from two or
more classes i.e. multiple inheritance is not supported. Thus every class has one and only one
base class.
a.cs
class aa : bb
class bb : cc
}
class cc : aa
Compiler Error
a.cs(13,7): error CS0146: Circular base class definition between 'cc' and 'aa'
class aa is derived from bb. Class bb in turn is derived from cc and cc is derived from aa. This
results in a circular definition. class aa is derived from bb and cc, as bb is derived from cc. As cc
is also derived from aa class, bb also derives from this class which is aa. Thus aa is derived from
aa which is a logical impossibility.
Equating Objects
a.cs
class zzz
a = b;
b = a;
class yyy
}
class xxx {
Compiler Error
C# has a very simple rule. It does not like you to equate different objects to each other. Thus an
object that looks like yyy cannot be equated to one that looks like xxx and vice versa. Thus the
error. Another example - you cannot take an int and equate it to a string . C# is extremely strict
when it comes to dealing with different data types.
a.cs
class zzz
a = b;
b = a;
class yyy
}
class xxx : yyy
Compiler Error
There is however one way out. On account of this way, one of the errors disappeared. The only
time we are allowed to equate dissimilar data types is when we derive from them. Lets explain
this in detail.
When we create an instance of yyy by saying new, we are creating two objects at one go, one
that looks like yyy and the other that looks like object. All classes in C# are finally derived from
object. As xxx is derived from yyy, when we say new xxx, we are creating 3 objects, one that
looks like yyy, one that looks like xxx and finally object.
Thus when we write a = b, b looks like xxx, yyy and object and as a looks like yyy, there is a
match at yyy. Consequence? No error. Even though a and b have the same values, using a we can
only access the members of yyy, even though had we used b we could access xxx also. We have
devalued the potency of a . The error arises at b = a, because the class yyy is less/smaller than the
class xxx . The class xxx has yyy and more. We cannot have a larger class on the right and a
smaller class on the left. a only represents a yyy whereas b expects a xxx which is a xxx and yyy.
The basic rule is that we can only equate dissimilar objects if they are derived from each other.
You can equate an object of a base class to a derived class but not vice versa.
a.cs
class zzz
a = b;
b = (xxx) a;
class yyy
Though we broke a C# rule on equating objects, we did not get an error because of the cast . A ()
is called a cast. Within the brackets we put the name of a class. A cast is the great leveler. When
we write b = a, C# expects the right hand side of the equal to to be a b i.e. a xxx . Instead it finds
a i.e. a yyy . So by applying a cast, we are for the moment converting the yyy object into an xxx.
This strategy satisfies the rules of C# on only equating similar objects. Remember it is only for
the duration of the line that a becomes a xxx and not a yyy.
a.cs
class zzz
a = (yyy) b;
b = (xxx) a;
}
class yyy
class xxx
Compiler Error
Unfortunately casting works only if one of the two classes is derived from the other. You cannot
cast any two objects to each other.
a.cs
class zzz
int i = 10;
char j = 'A';
i = j;
j = i;
}
Compiler Error
We are allowed to convert a char into a int as i = j but not the other way round as j = i.