What inheritance is
Inheritance lets one class build on another. The new class, called the derived or child class, automatically gets the members of an existing base or parent class, and then adds members of its own. You write the shared fields and methods once, in the base class, instead of copying them into every class that needs them.
Inheritance models an "is-a" relationship. A puppy is a dog, so a Puppy class can reasonably inherit from Dog: everything a dog has and does, a puppy has and does too, plus a few extras. A quick test before you reach for inheritance is to say the sentence out loud. "A puppy is a dog" makes sense. "A dog is a collar" doesn't, so if a dog needs a collar, give Dog a field of type Collar instead.
Inheritance is one of the classic pillars of object-oriented programming, alongside encapsulation, polymorphism and abstraction, and the later lessons in this chapter build on it.
The syntax
In C#, a class names its base class after a colon. Here is the lesson's Dog class and a Puppy that derives from it:
class Dog {
public string name;
public Dog(string name) { this.name = name; }
public void Bark() {
Console.WriteLine("Woof! I am " + name);
}
}
class Puppy : Dog {
public Puppy(string name) : base(name) { }
public void Whine() {
Console.WriteLine("whimper");
}
}
Three things are happening in Puppy:
class Puppy : Dogdeclares thatPuppyderives fromDog.public Puppy(string name) : base(name) { }is the constructor. The: base(name)part callsDog's constructor with the same name, so the inheritednamefield gets set. The body is empty because there is nothing else to do.Whineis new behaviour that only puppies have.
A Puppy object can now use both its own method and the inherited ones:
Puppy buddy = new Puppy("Buddy");
buddy.Bark(); // Woof! I am Buddy
buddy.Whine(); // whimper
Console.WriteLine(buddy.name); // Buddy
What a derived class can use
The access modifiers on the base class decide what the derived class can touch:
publicmembers, likenameandBark, work inPuppyas ifPuppyhad declared them.protectedmembers are visible inside derived classes but not to outside code.privatemembers still exist inside everyPuppyobject, but code inPuppycan't refer to them by name.- Constructors are not inherited. Each class declares its own and passes what the base class needs through
base(...).
The base constructor runs first
Creating a derived object always runs the base class's constructor before the derived constructor's body. When a constructor has no : base(...), C# calls the base class's parameterless constructor for you:
class Animal {
public Animal() {
Console.WriteLine("Animal constructor");
}
}
class Cat : Animal {
public Cat() {
Console.WriteLine("Cat constructor");
}
}
// new Cat() prints:
// Animal constructor
// Cat constructor
A derived object is also a base object
Because a puppy is a dog, a Puppy can go anywhere a Dog is expected:
Dog pet = new Puppy("Rex");
pet.Bark(); // Woof! I am Rex
// pet.Whine(); // compile error: the variable's type is Dog, and Dog has no Whine
The variable's declared type decides which members you can call. This idea is the starting point for polymorphism.
Two more rules complete the picture. A C# class can have only one base class, although it may also implement any number of interfaces. And every class ultimately derives from object, which is why methods like ToString() exist on everything.
Common mistakes and gotchas
- Leaving out
: base(name). Without it, C# tries to callDog()with no arguments.Dogonly has a constructor that takes a name, so the code doesn't compile. Omitting thePuppyconstructor entirely fails the same way, because the constructor C# generates also callsDog(). - Forgetting
public. Class members areprivateby default. If you writevoid Whine(), the callbuddy.Whine()from another class is rejected. - Using a private base member. Code in a derived class can't read the base class's private fields. Mark them
protectedif derived classes should see them. - Accidentally hiding a method. Declaring
public void Bark()again inPuppyhides the inherited one, and the compiler warns about it. Replacing behaviour properly usesvirtualandoverride, which method overriding covers. - Wrong capitalisation. C# is case-sensitive, and methods are conventionally PascalCase. The lesson calls
BarkandWhine, so a method namedwhinedoesn't match, andbuddy.Whine()fails to compile. - Inheriting just to reuse code. If the "is-a" sentence sounds wrong, use a field instead. Inheritance ties the two classes tightly: every change to the base class reaches the derived one.
The exercise, step by step
The lesson gives you Dog and a Solution class whose MainFunction creates a Puppy named "Buddy" and calls Bark() and Whine() on it. Your job is to write Puppy between them.
- Declare the class and its constructor. Write
class Puppy : DogsoPuppyinherits thenamefield and theBarkmethod. Give it a public constructor that takes astring nameand forwards it with: base(name), sinceDog's field still has to be set byDog's constructor. - Add the new behaviour. Inside
Puppy, addpublic void Whine()that prints"whimper"withConsole.WriteLine.Barkis already inherited, so this is the only method you write.
When the program runs, new Puppy("Buddy") calls the Puppy constructor, which passes "Buddy" up to Dog's constructor to set name. The inherited Bark() then prints Woof! I am Buddy, and Whine() prints whimper, matching the expected output line for line.
Key takeaways
class Child : ParentmakesChildinheritParent's members.- Use inheritance for "is-a" relationships, and a field for "has-a" ones.
- Constructors aren't inherited; forward arguments with
: base(...), and the base constructor runs first. - Public and protected members are usable in the derived class; private ones are not.
- A derived object can be stored in a variable of the base type, but only the base type's members are callable through it.
- C# allows one base class per class, and every class derives from
object.