class Dog
{
}
class BullDog : Dog
{
}
class Program
{
static void Main()
{
Dog dog2 = new BullDog();
BullDog dog3 = new BullDog();
}
}
When you use the base type as the reference type, you can only call members that are defined on the base type. You need to cast in order to use the members of the supertype.
So, if BullDog
defined a DoNotRelease
method, you could not call it from a Dog
reference directly.
In terms of var
- it will infer the more specific type. So if using new BullDog()
the inferred type will be BullDog
.
Normally when using inheritance you will also use overloading.
But consider the following:
static void Main()
{
Dog dog = new BullDog();
BullDog bulldog = new BullDog();
dog.Execute();
bulldog.Execute();
}
class Dog
{
public virtual void Execute()
{
Console.WriteLine("Execute Dog");
}
}
class BullDog : Dog
{
public new void Execute() // use new instead of override
{
Console.WriteLine("Execute BullDog");
}
}
This will print:
Execute Dog
Execute BullDog
You need to define a sub type if you want to access functions that are only available for that type. If you want to use operator overloading the way it's meant (with the override operator) you can use this subclass behavior without worrying about the current type.
--EDIT--
You asked for the difference between:
object a3 = new BullDog();
BullDog a3 = new BullDog();
Well, for starters, in the same scope this would give you a compiler error because a3 can't be defined twice. But let's say you define them in different scopes.
On object a3 you can only call methods that are avaible on object (Equals, GetHashCode, ToString, GetType()). If you want to use methods on it that are only avaible in the Dog class, you have to cast it to a Dog.
object a3 = new BullDog();
BullDog a4 = new BullDog();
if (a3 is Dog)
{
// only executes when a3 is a Dog
// a3 is for the compiler still of type object, so you can't call any other methods on it
}
Dog d1 = a3 as Dog; // cast it to a dog
if (d1 != null) // if d1 == null, then a3 was not of type dog and the cast returned null
{
d1.Execute(); // we know now that d1 is a dog and that it points to a dog instance so we can call a dog method on it.
}
a4.Execute();
lets define an other class :
class OtherDog : Dog
{
}
now you can define a list like this :
C# :
List<Dog> Dogs = new List<Dog>();
Dogs.Add(new BullDog());
Dogs.Add(new OtherDog());
you have a list with Dog type , but can add to it BullDog and OtherDog type to it
this is one of the OOP subjects name "Polymorphism"
ex2 :
lets think you want to develop a paint :
class Shape ()
{
virtual public void Draw()
{
}
}
class Rectangle : Shape ()
{
override public void Draw()
{
}
}
class Circle : Shape ()
{
override public void Draw()
{
}
}
void main ()
{
List<Shape> Shapes = new List<Shape>();
Shapes.Add(new Rectangle());
Shapes.Add(new Circle());
Shape[1].Draw(); //Draw a rectangle
Shape[2].Draw(); // Draw a circle
}
if you need more details comment me to edit my reply for more details
thansk , Ali
You don't need Dog dog2 = new BullDog()
, you will be able to pass your BullDog
to any method expecting a Dog
.
Take a look at http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming
Q: "What is the difference between using Dog as a reference vs BullDog as a reference?"
A: If you have a Dog reference, any additional methods/properties/fields you add to the derived type BullDog will not be publicly accessible.
E.g. if you had:
public class Dog
{
public virtual void Bark()
{
Console.WriteLine("Woof");
}
}
public class BullDog : Dog
{
public override void Bark()
{
Console.WriteLine("BOWF!");
}
public void Slobber()
{
Console.WriteLine("I cannot control my drool :(");
}
{
... you wouldn't be able to do this:
Dog baseDog = new BullDog();
baseDog.Slobber(); // error -- Dog doesn't know how to slobber.
... as the method doesn't exist for the base type.
Also, depending on whether you have a base/derived reference, there are also some subtle problems that can occur if you carelessly use the new operator. However, these are very rare occurrences in my experience (see Wouter de Kort's post, as he just posted a better explanation as I was typing it up).
Q: "I have an habit of using var dog3 = new BullDog(); which is similar to BullDog dog2 = new BullDog(); When do we need to use Dog dog2 = new BullDog();?"
A: You may not even know what type of Dog
you're getting, all you know is .. it's a Dog
. Consider...
public static class DogFactory
{
public static Dog CreateMysteryDog()
{
return new Shitzu();
}
}
Dog dog = DogFactory.CreateMysteryDog(); // what is the concrete type of Dog?
DogFactory returns a Dog
reference, not a Shitzu
reference, so you have to use the base type. In this case, var will be a Dog
rather than a Shitzu
, too.
EDIT: To address the additional question from the comments:
static void TakesDog(Dog theDog) { ... }
static void TakesBulldog(Bulldog theBulldog) { ... }
static void TakesObject(object theObject) { ... }
static void Main()
{
//Given these declarations...
object dog = new BullDog();
Dog dog2 = new BullDog();
BullDog dog3 = new BullDog();
//These calls will work because a BullDog is a Dog:
TakesDog(dog2);
TakesDog(dog3);
//this call will work because a Bulldog is a Bulldog:
TakesBulldog(dog3);
//and these calls will ALL work because all Dogs are Objects:
TakesObject(dog);
TakesObject(dog2);
TakesObject(dog3);
//However, these calls will fail because an Object or Dog is not
//necessarily a Bulldog,
//EVEN THOUGH our current dog and dog2 are indeed references to Bulldogs:
TakesBulldog(dog);
TakesBulldog(dog2);
//An explicit conversion is necessary to make the above calls work:
TakesBulldog(dog2 as Bulldog); //works given the current reference
TakesBulldog((Bulldog)dog2); //works given the current reference
TakesBulldog(dog as Bulldog); //ditto
TakesBulldog((Bulldog)dog); //ditto
//but if we change the value of dog2 to some other dog:
dog2 = new Labrador();
//the above calls now fail:
TakesBulldog(dog2 as Bulldog); //passes null into the method
TakesBulldog((Bulldog)dog2); //throws InvalidCastException
//you can avoid problems by checking the true type:
if(dog2 is Bulldog) //interrogates the type of the referenced object
TakesBulldog((Bulldog)dog2); //works
else
TakesDog(dog2); //general fallback case
//Object is similar but even more basic:
dog = "I'm a dog"; //now dog is a System.String
//this call still works:
TakesObject(dog);
//but these will fail:
TakesDog(dog);
TakesBulldog(dog);
}
One last thing to understand:
//given these declarations:
object dog = new BullDog();
BullDog dog2 = new BullDog();
//even though dog is a BullDog, attempting to call BullDog-specific
//members (methods, properties, fields) will fail:
dog.Drool();
//you may only call members as specific as the object type of the
//variable holding the reference:
dog.ToString(); //defined by Object. If you've overridden it in Dog or BullDog,
//you'll get that implementation
dog2.Drool(); //works because we know from the variable that dog2 is a BullDog.