.. Copyright (C) Dave Parillo. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with Invariant Sections being Forward, and Preface, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". .. index:: single: constructors Constructors ============ When we allocate storage for a built-in type, we use the name of the type and a name for the variable: .. code-block:: cpp int x; As we saw in the previous section, the syntax for user-defined types is the same: .. code-block:: cpp talk say; User-defined types use special functions to *construct* an object using the class definition. We call these special functions *class constructors*. Constructors are very similar to regular free functions, but there are a few special rules: - A constructor is a **class member** function - The function name is the **same name** as the class name - A constructor has **no return type** **All** classes must have at least 1 constructor. If you do not write one, then compiler will try to create it automatically. The ``talk`` class works because it used an automatically defined default constructor generated by the compiler. .. tb-code:: cpp :name: ac-class-construct-ex1 #include struct talk { void hello() { std::puts("Hello, world!"); } }; int main() { talk say; // Create an object from a class say.hello(); // Call a function in the object } Although we did not need to create a constructor for the ``talk`` class, we could have. This constructor doesn't change how our code functions in any way. The compiler would have generated the code ``talk() {}`` for us. .. tb-code:: cpp :name: ac-class-construct-ex2 #include struct talk { talk() {} // default constructor void hello() { std::puts("Hello, world!"); } }; int main() { talk say; // Create an object from a class say.hello(); // Call a function in the object } .. cpp:: 11 C++11 adds :lang:`default ` which instructs the compiler to create the default constructor for us. .. code-block:: cpp talk() = default; Since C++11 this syntax is preferred over ``talk() {}`` Object life cycle ----------------- In C++, objects get created, used, and destroyed. Constructors, assignment functions, and destructors control the life cycle of objects: creation, copy, move, and destruction. Like the default constructor, C++ defines default operations for other parts of an object life cycle. The default operations are a set of related operations that together implement the life cycle semantics of an object. The list of default operations since C++11 is: ==================== ======================= Operation Function Signature ==================== ======================= default constructor ``X()`` copy constructor ``X(const X&)`` copy assignment ``operator=(const X&)`` move constructor ``X(X&&)`` move assignment ``operator=(X&&)`` destructor ``~X()`` ==================== ======================= We will be discussing these operations more over the next several chapters. Let's improve our ``talk`` class by making it possible to say more than one thing and to set the default text in a constructor: .. tb-code:: cpp :name: ac-class-construct-ex3 #include #include using std::string; struct talk { string text_; // a variable to store what we want to say talk() // a new default constructor : text_ ("Hello, world!") { } talk(const string& value) // a one argument constructor : text_ (value) { } void message() { std::puts(text_.c_str()); } }; int main() { talk say; // Create the default object say.message(); say.text_ = "Something else"; say.message(); // Create a non-default object talk talk("The 80's were a long time ago."); talk.message(); } Note that we also changed the name of our function from ``hello`` to ``message``. Our old function name is no longer very appropriate since we can say more things than just *Hello, world!*. .. cpp:: 11 Since C++11, this syntax for constructors: .. code-block:: cpp talk(const string& value) : text_ (value) { } is preferred. This is called *initializer list syntax*. The general format is: .. code-block:: cpp ClassName(arguments) : class_member1 {expression1}, class_member2 {expression2}, class_memberN {expressionN} . . . { } Initializer list expressions can be surrounded by ``( )`` or ``{ }``. Prior to C++11, standard function syntax was used. It is still allowed, but initializer list syntax is preferred. .. code-block:: cpp ClassName(arguments) { class_member1 = expression1; class_member2 = expression2; class_memberN = expressionN; } In C++11, it is also permissible to initialize class members with constants directly in the class when declared. In-class initialization is preferred because it makes it explicit that the same value is expected to be used in all constructors, avoids repetition, and avoids maintenance problems. It leads to the shortest and most efficient code. Consider the following: .. code-block:: cpp class bad_init { int i; string s; int j; public: bad_init() :i{666}, s{"nothing"} { } // j is uninitialized bad_init(int value) :i{value} {} // s is "" and j is uninitialized // ... }; How would a maintainer know whether ``j`` was deliberately uninitialized (probably a poor idea anyway) and whether it was intentional to give ``s`` the default value ``""`` in one case and ``nothing`` in another? This is almost always a bug. Forgetting to initialize a member often happens when a new member is added to an existing class. All these problems are easily fixed with in-class initializers: .. code-block:: cpp class ok_init { int i {666}; string s {"ok"}; int j {0}; public: ok_init() = default; // all members initialized to default values ok_init(int value) :i{value} {} // s and j initialized to their defaults // ... }; A common error is to confuse constructors with other functions. .. tb-choice:: :name: mc-class-constructors-1 :random: Given: .. code-block:: cpp class date { int y, m, d; public: date (); date (int y, int m, int d); date (const date& d); date get_date (); }; Which lines are valid constructor declarations? (Choose all that apply) - ``date ();`` + This is the ``default constructor``. The default constructor takes no arguments. - ``date (int y, int m, int d);`` + Constructors may take arguments. - ``date (const date& d);`` + There is no reason why a constructor can't take an object of its own type as a function parameter. This is a special constructor called a ``copy constructor``. - ``date get_date ();`` - This is **not** a constructor. It is free function named ``get_date`` that returns a ``date``. - ``int y, m, d;`` - This is **not** a constructor line. It is the declatation of 3 variables used in the class. Class invariants ---------------- A struct is acceptable to define a type as long as *every* struct member may be assigned **any** value at any time. If this is not true for your type, then we say that your type has :term:`invariants`. Class invariants are guarantees made by your type. Invariants represent things that must hold true for your class to be valid. Let say we need to prevent ``talk`` from allowing zero length strings in the member ``text_``. Currently, since everything is public, but it is easily fixed: .. tb-code:: cpp :name: ac-class-construct-ex4 #include #include using std::string; class talk { public: talk() : text_ ("Hello, world!") { } talk(const string& value) : text_ {value.empty()? "default text": value} { } string message() { return text_; } void message(string value) { if (value.empty()) return; text_ = value; } private: string text_; }; int main() { talk say; std::cout << say.message() << '\n'; say.text("Something else"); std::cout << say.message() << '\n'; say.text(""); std::cout << say.message() << '\n'; } .. admonition:: Try This! Without running this program, can you predict it's output? Our class now enforces its *invariants* that it will never allow the ``talk`` text to be empty (we're a talkative talk class). We made several changes: - The member ``text_`` is now private. - A function ``void text(string value)`` was added. This was needed because we made ``text_`` private. Without this function, the only way to set the text was in the constructor. - Added an additional check to our one argument constructor to enforce the "can't be empty" invariant. .. admonition:: Try This!! Modify the last example so that it accepts an additional class member variable to repeat what ``talk`` says more than once. ----- .. admonition:: More to Explore - From cppreference.com - :lang:`Classes ` - :lang:`Default constructors ` - From C++ Core Guidelines - :guidelines:`Constructors ` - :guidelines:`Prefer in-class iniitalizers ` - Default operations: :guidelines:`rule of zero ` and :guidelines:`rule of five ` - :guidelines:`Concrete types ` - `CplusPlus.com classes tutorial `__. - And if you read the tutorial, then also review :guidelines:`Avoid protected data `