CS 70

Constructors

A constructor is used to create an instance of a class (i.e., an object). It is a special kind of function with a special job.

  • LHS Cow speaking

    In C++ there are a few different kinds of constructors that are used for different purposes. In this lesson, we'll discuss a couple of particularly important ones.

The Constructor's Job

The constructor's job is to initialize the object and make it ready for use. The memory the constructor is initializing has already been allocated (e.g., at the opening curly brace of the function), but until the constructor runs, the memory has not yet been initialized.

Thus, the constructor's main job is to initialize the data members of the object being constructed. (Although it can do other things as well.)

Parameterized Constructors

A parameterized constructor is exactly what it sounds like: a constructor that has parameters.

  • RHS Cow speaking

    These constructors should look pretty familiar; for example, the highlighted code in the following snippet from cow.hpp:

class Cow {
  public:
    // We can only have a Cow if we know
    // how many spots it has and how old it is
    Cow(int numSpots, int age);
    Cow() = delete;
...

A parameterized constructor must be explicitly invoked. For example, here are two highlighted lines from main.cpp that invoke the parameterized constructor of Cow:

int main() {
    Cow bessie{3, 12};
    const Cow mabel{1, 2};
  • Horse speaking

    Hay, what's up with the curly braces there? I'm used to parentheses.

  • LHS Cow speaking

    Good catch! Hold onto that question and we'll get to it in a page or two.

The Default Constructor (No Parameters)

A constructor with no parameters has a special name: the default constructor.

This constructor can be invoked explicitly as

Sheep mead{};

Default Initialization Uses the Default Constructor

But also, and maybe more importantly, the default constructor is the constructor used for default initialization. For instance,

Sheep mead;

would also invoke the default constructor of class Sheep to initialize mead.

  • RHS Cow speaking

    Note that mead is not “uninitialized” or “null” or “none” or anything you've seen in another language!

  • Sheep speaking

    Yeah, I'm right here! I'm not “none”! I'm some!

  • LHS Cow speaking

    It also doesn't have an indeterminate value like a default-initialized int would.

  • RHS Cow speaking

    The variable mead contains an actual object that was initialized using a specific constructor: the constructor with no parameters.

  • LHS Cow speaking

    The default constructor.

Default initialization comes up in many contexts and sometimes it can be subtle. For example,

Sheep herd[10];

creates an array of ten Sheep objects. How are they initialized? Using the default constructor!

So that one line of code actually calls Sheep's default constructor ten times.

The Default Constructor Can Be Automatically Synthesized

For convenience (unless we tell C++ otherwise), every class has a default constructor, even if you don't define one!

  • Dog speaking

    Really? What does it do??

  • LHS Cow speaking

    It does the most reasonable thing for a class with no explicitly defined constructor.

If you don't define a constructor, the compiler synthesizes a default constructor that initializes all member variables exactly as shown in the class definition. So if we didn't specify any initialization in the class definition,

  • Member variables that hold primitive types (such as int , double, etc.) have indeterminate values.
  • Member variables that hold objects of class type are initialized using their default constructors.

We can avoid this potentially dangerous issue for primitive types by specifying an initialization for member variables when we declare them in the class definition. For example, in our Cow class, we could have written

...

 private:
    // The number of spots and an age can't be negative...
    int numSpots_ = 4;
    int age_ = 0;
};
...
  • Dog speaking

    Cool!

  • LHS Cow speaking

    Yeah, it's pretty handy. Except…

When You Don't Want a Default Constructor

If you don't want a default constructor, it isn't enough to just not define one, because in that case C++ will synthesize one automatically. Instead we must use some new syntax—= delete—to tell C++ that the class should not have a default constructor.

Here it is highlighted in our code

class Cow {
 public:
    // We can only have a Cow if we know
    // how many spots it has and how old it is
    Cow(int numSpots, int age);
    Cow() = delete;
...

In this context, specifying = delete tells the compiler to give an error if we write any code that tries to use this function.

  • Cat speaking

    So it's like it doesn't exist.

  • LHS Cow speaking

    Pretty much.

  • Duck speaking

    But wait, why would we want to get rid of a function? If C++ will automatically write a default constructor for us, why not just let it?

  • Pig speaking

    Yeah, I want MORE constructors!!

  • LHS Cow speaking

    Well, sometimes it just doesn't make sense to default initialize. Maybe we don't know what the “default” Cow should be. Maybe we really need to be given the age and number of spots in order to create a Cow.

  • RHS Cow speaking

    And sometimes C++'s automatically synthesized code wouldn't be correct. Using = delete says to C++, “I know you want to help, but not this time!”

In our running example, we can see that the default constructor for Cow has been effectively removed.

Because we removed the default constructor, the following code would no longer be allowed:

Cow buttercup; // Would cause a compile error!
Cow herd[5];   // Would cause a compile error!
  • LHS Cow speaking

    There are more special kinds of constructors, but we'll leave those for another time.

Check-In Questions

Which of the following are true about constructors?

We can stop the compiler synthesizing a default constructor for us by using the syntax:

  • Duck speaking

    Why did they choose = delete? Why not = disable or = deny or something?

  • Bjarne speaking

    I already had delete as a keyword in the language, so it seemed easiest to just reuse it here.

  • LHS Cow speaking

    Oh Bjarnie, you're such a character!

(When logged in, completion status appears here.)