Constructors
We’ll often want to initialize, or set the initial value of, some of our fields when creating a new object from a class. Constructors allow us to do so.
In C#, constructors have the same name as the class and are most often declared public (though they can have any other valid access modifier). They are declared without a return type. Any function that is named the same as the class and has no return type is a constructor.
Here is an example of a constructor definition within the HelloWorld
class:
|
|
This constructor allows us to create HelloWorld
objects with custom
messages. The assignment this.message = message
assigns the value
passed into the constructor to the field message
. Here’s how we
might use it:
HelloWorld goodbye = new HelloWorld("Goodbye World");
goodbye.SayHello(); // prints "Goodbye World"
It’s not required that every class have a constructor. If you don’t
provide one, the C# compiler will generate an empty constructor for
you, known as a default constructor. For example, when we left out a
constructor in our HelloWorld
class above, the compiler created the
following constructor for us:
public HelloWorld() {}
While this can be convenient, you almost always want to provide a constructor to properly initialize your objects.
Overloading Constructors
We can provide multiple constructors for a given class in order to allow for different initialization scenarios. This is known as constructor overloading. When providing multiple constructors, we must ensure that each has a different collection of arguments, as determined by the number, order, and type of the constructor arguments.
Let’s make some changes to our Student
class.
|
|
The first constructor allows for the creation of Student
objects
where the code creating the object provides initial values for each of
the fields. The second allows for the creation of Student
objects
with only name
and studentId
. The first constructor would be
most useful for creating a transfer student, where credits and a GPA
might already be non-zero. However, for all new students, it would be
safe to initialize numberOfCredits
and gpa
to be 0.
A better way to write the above constructors would be this:
|
|
In the example above on line 17, we use : this()
to invoke another
constructor within the same class. In this case, the second constructor calls
the first with default values for numberOfCredits
and gpa
. We haven’t seen
this syntax before but we’ll discuss it more in inheritance
.
This is a good practice not only because it makes your code shorter, but also because it allows any initialization behavior that may be carried out beyond just initializing variables to be contained in a smaller number of constructors. In other words, constructors can share initialization code. Notice from this example that a constructor doesn’t need to require an initial value for each field as an argument.
When defining constructors, think about:
- Which fields must be initialized for your class to work properly? Be sure you initialize every such field.
- Which fields should be initialized by the user creating an object, and which should be initialized by the class itself?
- What are the use-cases for your class that you should provide for?
Check Your Understanding
True or false, a constructor is required for every class.
Let’s take a look at a class called Dog
.
|
|
What line of code would be appropriate for us to declare an instance of the Dog
class called myDog
and give it the name, “Bernie”, and the breed, “beagle”?
Dog myDog = new Dog(Bernie, beagle);
Dog myDog = new Dog("Bernie", "beagle");
Dog Bernie = new Dog("Bernie", "beagle");