Constructors and Destructors Outline z Constructors and Destructors

  • Slides: 56
Download presentation
Constructors and Destructors

Constructors and Destructors

Outline z. Constructors and Destructors y. Default and compiler-generated y. Overloading y. Member initialization

Outline z. Constructors and Destructors y. Default and compiler-generated y. Overloading y. Member initialization vs. assignment y. Initializing const, reference and static members y. Copy constructor y. Assignment operator y. Constructors as type conversion operators y. Destructors

Declaring and initializing simple variables z. When variables of native types are declared there

Declaring and initializing simple variables z. When variables of native types are declared there is no question about how much memory to allocate z. Initialization is the process of storing a value in newly declared variables

Initializing simple variables int counter = 0; char* owner = NULL; char name[] =

Initializing simple variables int counter = 0; char* owner = NULL; char name[] = “C++”; double coef[3] = { 0, 1. 2, 3. 0 };

Initializing class objects y. Classes are complex (derived) types y. They may have many

Initializing class objects y. Classes are complex (derived) types y. They may have many components y. Example: Employee class has xname, address, id, etc. y. Declaration of a variable that is a class (instantiating an object) requires the ‘construction’ of an object by setting aside the required blocks of memory.

Initializing objects z. Constructors are special class methods that create an object of that

Initializing objects z. Constructors are special class methods that create an object of that class ythey have the same name as their class y. Example: y. Class Employee x{ public: x Employee() {}; // default constructor

What constructors do z. Have same name as the class z. Are called automatically

What constructors do z. Have same name as the class z. Are called automatically when class object declared z. Initialize (non-static) members y. Employee() { id = 0; } z. Allocate memory for dynamic members y. Employee() { char* nameptr = new char[20]; } z. Allocate any needed resources

Date class in C++ class Date { public: // services Date(); unsigned get. Month();

Date class in C++ class Date { public: // services Date(); unsigned get. Month(); void incr. Day(); unsigned get. DOW(); // more services. . . private: // state unsigned year, day, month; }

Constructors for the Date class default - all decisions are made for you Date

Constructors for the Date class default - all decisions are made for you Date today; initializing - you set basic parameters Date today(9, 20, 1999); copy - creates an object that is a copy of another object Date monday(today);

Constructors for the Date class Date { public: // default constructor Date(); // explicitly

Constructors for the Date class Date { public: // default constructor Date(); // explicitly specifying m, d, y Date(unsigned m, unsigned d, unsigned y); // copy constructor Date(const Date& _date); // parsing a string MM/DD/YYYY Date(const string& Date. Str);

When do constructors get called? z. Block local (automatic) object z. Dynamically allocated object

When do constructors get called? z. Block local (automatic) object z. Dynamically allocated object z. Class argument passed by value z. Class object returned by value z. Class member that is an object z. Array element z. Temporary object z. Local static object z. Global object

Local object { Date today; // constructor // implicitly called … } // destructor

Local object { Date today; // constructor // implicitly called … } // destructor implicitly // called here

Dynamic object { pstr = new string(“ 5113”); . . . delete pstr; //

Dynamic object { pstr = new string(“ 5113”); . . . delete pstr; // destructor called. . . }

Default constructor z. Takes no arguments, or z. All arguments have default values Date:

Default constructor z. Takes no arguments, or z. All arguments have default values Date: : Date() {…} Date: : Date(unsigned m = 0, unsigned d = 0, unsigned y = 0) { … }

Date: : Date() constructor Date: : Date () { time_t clock = time(0); struct

Date: : Date() constructor Date: : Date () { time_t clock = time(0); struct tm* tmptr = localtime(&clock); month = tm_month; day = tmptr->tm_day; year = 1900 + tmptr->tm_year; }

Default constructor (cont. ) z. Called when object declared without any arguments Date d;

Default constructor (cont. ) z. Called when object declared without any arguments Date d; string s;

Compiler-generated constructor z. What if we do not supply any constructor for a class?

Compiler-generated constructor z. What if we do not supply any constructor for a class? z. Compiler generates one with an empty body Date() {}; z. No data members initialized z. Do not rely on compiler-generated constructors

Disabling a default constructor z. Default constructors do not make sense for some classes

Disabling a default constructor z. Default constructors do not make sense for some classes yclasses with no reasonable defaults class Bank. Account {. . . }; Bank. Account ba; // nameless account?

Disabling a default constructor (cont). z. Solution: make a default constructor private Bank. Account

Disabling a default constructor (cont). z. Solution: make a default constructor private Bank. Account {. . . private: Bank. Account(); } z. Prevents compiler from supplying one Bank. Account ba; // will not compile

Constructing arrays of objects z. A default constructor is needed yuser- or compiler-supplied Complex

Constructing arrays of objects z. A default constructor is needed yuser- or compiler-supplied Complex cmplarr[10]; Date datearr[20]; z. There is no way to call constructors with arguments (non-default) for array members

Arrays of objects and nondefault constructors z. Trick: declare a pointer to an array

Arrays of objects and nondefault constructors z. Trick: declare a pointer to an array of objects z. Allocate and initialize each object in a loop Date* dates[31]; for (int day = 0; day < 31; ++day) { dates[i] = new Date(9, day, 1999); }

Multiple constructors z. What if you wanted your program to be able to create

Multiple constructors z. What if you wanted your program to be able to create Date objects in a variety of formats? y. Date today(9, 20, 1999); y. Date today(“Sept. , 20, 1999”); y. Date today(9, 20, 1999), same_as_today; same_as_today(today); z. To do this we must have different versions of the Date constructor.

Overloading constructors z. Multiple ways to initialize a Date objects yfrom Month, Day, Year

Overloading constructors z. Multiple ways to initialize a Date objects yfrom Month, Day, Year yfrom a date string in a known format yfrom another Date object y… z. Overloaded constructors ydifferent signatures (types and numbers of arguments)

Calling overloaded constructors Date today; // default constructor // explicitly specify m, d, y

Calling overloaded constructors Date today; // default constructor // explicitly specify m, d, y Date fdc(12, 31, 2000); // initialize date from string Date eoq(“ 12/12/1998”); // from another date object Date eoq 2(eoq);

Common tasks of overloaded constructors z. Checking arguments z. Incrementing the number of instances

Common tasks of overloaded constructors z. Checking arguments z. Incrementing the number of instances z. All Date constructors could call a private class method to verify input and assign values to private data members z Date: : assign(month, day, year)

Date: : assign method Date: : Date () { // initialize struct tm* tmptr.

Date: : assign method Date: : Date () { // initialize struct tm* tmptr. . . // assign checks its arguments assign(tmptr->tm_month, tmptr->tm_mday, 1900 + tmptr->tm_year); }

Date: : assign method Date: : Date (constr string Date. Str) { // parse

Date: : assign method Date: : Date (constr string Date. Str) { // parse m, d, y from Date. Str. . . // assign checks its arguments assign(m, d, y); }

Date: : assign method void Date: : assign(unsigned _month, unsigned _day, unsigned _year) {

Date: : assign method void Date: : assign(unsigned _month, unsigned _day, unsigned _year) { set. Month(_month); set. Day(_day); set. Year(_year); // counter of Dates instantiated num. Created++; }

Direct assignment from the constructor z. Rather than calling a private ‘assign’ function, the

Direct assignment from the constructor z. Rather than calling a private ‘assign’ function, the constructor could do the assignment itself. z. Advantage of using ‘assign’ is the isolation of the verification process to that function.

Assignment vs. initialization in constructors z. Assignment yin the constructor body Date: : Date(unsigned

Assignment vs. initialization in constructors z. Assignment yin the constructor body Date: : Date(unsigned m, unsigned d, unsigned y) { month = m; day = d; year = y; }

Assignment vs. initialization in constructors z. Initialization yin the initialization list Date: : Date(unsigned

Assignment vs. initialization in constructors z. Initialization yin the initialization list Date: : Date(unsigned m, unsigned d, unsigned y) : Initialization list month(m), day(d), year(y) {}; Empty function body

Assignment vs. initialization in constructors class Student { private: string name; public: Student(string a.

Assignment vs. initialization in constructors class Student { private: string name; public: Student(string a. Name) { name = a. Name; }; . . .

Why initialization is preferred to assignment z. When a Student object is constructed, ya

Why initialization is preferred to assignment z. When a Student object is constructed, ya default constructor for string name is called Student(string a. Name) { string name = a. Name }; ythis allocates (1 byte of) memory yinside Student: : Student body, string assignment operator is called ymemory is freed and allocated again

A better way of initialization z. Uses initialization z. Avoids allocation, deallocation, reallocation for

A better way of initialization z. Uses initialization z. Avoids allocation, deallocation, reallocation for name Student(string a. Name) : name(a. Name) {};

Problem: Order of initialization z. Initialization takes place in the order that variables were

Problem: Order of initialization z. Initialization takes place in the order that variables were declared z. Not the order in which members are in the initialization list! z. Subtle dependencies possible which could cause problems (next slide)

Pitfalls of initialization lists class my_string { private: char* rep; unsigned len; public: my_string(const

Pitfalls of initialization lists class my_string { private: char* rep; unsigned len; public: my_string(const char* cp) : len(strlen(cp)), rep(new char[len+1]) {}; z. Member len initialized after rep z. But rep uses len. . .

Initializing const and ref members z. Assignment to constants and references prohibited z. Initialization

Initializing const and ref members z. Assignment to constants and references prohibited z. Initialization required z. Const and reference members must be initialized in the constructor initialization lists

Initializing static and global objects z. Few reasons to have global objects z. Initialized

Initializing static and global objects z. Few reasons to have global objects z. Initialized in the order of declaration z. Dependencies between global objects in different files z. If you must, make them local static z. Initialized when control thread first passes over

Copy constructor z. Initializes a new object from another, existing one z. Signature: Class:

Copy constructor z. Initializes a new object from another, existing one z. Signature: Class: : Class(const Class&);

Copy constructor for class Date: : Date(const Date& date) { // no need to

Copy constructor for class Date: : Date(const Date& date) { // no need to check passed date arg month = date. month; day = date. day; year = date. year; }

Uses of the copy constructor z. Implicitly called in 3 situations ydefining a new

Uses of the copy constructor z. Implicitly called in 3 situations ydefining a new object from an existing object ypassing an object by value yreturning an object by value

Copy constructor: defining a new object Date eosem(“ 12/20/1999”); // init 2 local objects

Copy constructor: defining a new object Date eosem(“ 12/20/1999”); // init 2 local objects from eosem Date eosem 2(eosem); // pass by value Date eosem 3 = eosem; // return value // init a dynamic object from eosem Date pdate = new Date(eosem);

Copy constructor: passing objects by value //copy ctor called for each value arg unsigned

Copy constructor: passing objects by value //copy ctor called for each value arg unsigned date. Diff(Date d 1, Date d 2); . . . Date today; Date eosem(12, 20, 1999); cout << date. Diff(eosem, today);

Avoiding copy constructors z. To avoid unnecessarily calling copy constructors z. Do not pass

Avoiding copy constructors z. To avoid unnecessarily calling copy constructors z. Do not pass object by value; pass by const ref unsigned date. Diff(const Date& d 1, const Date& d 2);

Compiler-supplied copy constructor z. Copies members bitwise z. OK for built-in types z. Problematic

Compiler-supplied copy constructor z. Copies members bitwise z. OK for built-in types z. Problematic for resources owned by object z. Slack bytes problem

Compiler-supplied copy constructor: problems class Date { char* char. Rep; // owned by Date

Compiler-supplied copy constructor: problems class Date { char* char. Rep; // owned by Date today. . . m: 9 d: 20 y: 1999 char. Rep* Date today; Date today 2(today); 9/20/1999 today 2 m: 9 d: 20 y: 1999 char. Rep*

Shallow copy by default z. The problem with the compiler supplied copy constructor is

Shallow copy by default z. The problem with the compiler supplied copy constructor is that it is a shallow copy constructor. z. In the last example, both today and today 2 consist of pointers set to the same block of memory. z. Thus, a change to one date will affect the other.

Constructors as type conversion operators z. Constructors take a single argument of a given

Constructors as type conversion operators z. Constructors take a single argument of a given type yby value or by const reference z. They implicitly convert it into the passed type (see example on next 2 slides)

Constructors as type conversion operators class my_string { public: my_string(unsigned slen) : rep =

Constructors as type conversion operators class my_string { public: my_string(unsigned slen) : rep = new char[slen+1], len(slen) { memset(rep, ‘ ‘, len); }; private: char* rep; unsigned len;

Constructors as type conversion operators my_string s = ‘a’; zchar ‘a’ is promoted to

Constructors as type conversion operators my_string s = ‘a’; zchar ‘a’ is promoted to unsigned 97 za string of 97 spaces is created zprobably not the desired result z. Keyword explicit does not allow implicit conversions explicit my_string(unsigned slen);

Destructors z. Called automatically when local objects go out of scope z. Called implicitly

Destructors z. Called automatically when local objects go out of scope z. Called implicitly when dynamic objects are deleted

Assignment operator z. Similar to the copy constructor, but z. Re-initializes already constructed objects

Assignment operator z. Similar to the copy constructor, but z. Re-initializes already constructed objects Date today; // copy constructor. . . today = “ 9/20/1999”; z. Need assignment operator accepting char*

Assignment operator Class Date { Date& operator=(const char* d. Cptr); . . . }

Assignment operator Class Date { Date& operator=(const char* d. Cptr); . . . } Date: : operator=(const char* d. Cptr) { // parse date. Cptr into m, d, y assign(m, d, y); }

Assignment operator z. New C++ feature: overloading operators z. Operator overloading - next lecture

Assignment operator z. New C++ feature: overloading operators z. Operator overloading - next lecture z. Compiler generates a default assignment operator if you do not define one ybitwise copy only

Assignment operator z. Bitwise copy ok for classes like Date ymembers of simple types

Assignment operator z. Bitwise copy ok for classes like Date ymembers of simple types only yno pointers => no remote ownership z. What happens if we bitwise copy an object owning a resource? y. Same problem as with default copy constructors

Rule of Big Three z. If a class has any of ycopy constructor ydestructor

Rule of Big Three z. If a class has any of ycopy constructor ydestructor yassignment operator z. It needs all three z. Destructor usually shows up first z. Exception: when destructor only decrements number of instances