Upload
ami-rose
View
240
Download
7
Embed Size (px)
Citation preview
Constructors and Destructors
OutlineConstructors and Destructors
Default and compiler-generated Overloading Member initialization vs. assignment Initializing const, reference and static members Copy constructor Assignment operator Constructors as type conversion operators Destructors
Declaring and initializing simple variables
When variables of native types are declared there is no question about how much memory to allocate
Initialization is the process of storing a value in newly declared variables
Initializing simple variables
int counter = 0;
char* owner = NULL;
char name[] = “C++”;
double coef[3] = { 0, 1.2, 3.0 };
Initializing class objects
Classes are complex (derived) types They may have many components Example: Employee class has
name, address, id, etc.
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
Constructors are special class methods that create an object of that class they have the same name as their class Example: Class Employee
{ public: Employee() {}; // default constructor
What constructors do
Have same name as the classAre called automatically when class
object declaredInitialize (non-static) members
Employee() { id = 0; } Allocate memory for dynamic members
Employee() { char* nameptr = new char[20];}
Allocate any needed resources
Date class in C++class Date {
public: // services
Date();
unsigned getMonth();
void incrDay();
unsigned getDOW();
// more services...
private: // state
unsigned year, day, month;
}
Constructors for the Date class
default - all decisions are made for youDate today;
initializing - you set basic parametersDate today(9,20,1999);
copy - creates an object that is a copy of another objectDate monday(today);
Constructors for the Date classclass 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& DateStr);
When do constructors get called?Block local (automatic) objectDynamically allocated objectClass argument passed by valueClass object returned by valueClass member that is an objectArray elementTemporary objectLocal static objectGlobal object
Local object
{
Date today; // constructor
// implicitly called
…
} // destructor implicitly // called here
Dynamic object
{
pstr = new string(“5113”);
...
delete pstr; // destructor called
...
}
Default constructor
Takes no arguments, orAll 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 tm* tmptr = localtime(&clock);
month = tm_month;
day = tmptr->tm_day;
year = 1900 + tmptr->tm_year;
}
Default constructor (cont.)
Called when object declared without any arguments
Date d;
string s;
Compiler-generated constructor
What if we do not supply any constructor for a class?
Compiler generates one with an empty body
Date() {};
No data members initializedDo not rely on compiler-generated
constructors
Disabling a default constructor
Default constructors do not make sense for some classes classes with no reasonable defaults
class BankAccount { ... };
BankAccount ba; // nameless account?
Disabling a default constructor (cont).Solution: make a default constructor private
BankAccount {
...
private:
BankAccount();
}
Prevents compiler from supplying oneBankAccount ba; // will not compile
Constructing arrays of objects
A default constructor is needed user- or compiler-supplied
Complex cmplarr[10];
Date datearr[20];
There is no way to call constructors with arguments (non-default) for array members
Arrays of objects and non-default constructors
Trick: declare a pointer to an array of objectsAllocate 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
What if you wanted your program to be able to create Date objects in a variety of formats? Date today(9,20,1999); Date today(“Sept.,20, 1999”); Date today(9,20,1999), same_as_today;
same_as_today(today);To do this we must have different
versions of the Date constructor.
Overloading constructors
Multiple ways to initialize a Date objects from Month, Day, Year from a date string in a known format from another Date object …
Overloaded constructors different signatures (types and numbers of
arguments)
Calling overloaded constructorsDate 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 eoq2(eoq);
Common tasks of overloaded constructors
Checking argumentsIncrementing the number of
instancesAll Date constructors could call a
private class method to verify input and assign values to private data members
Date::assign(month, day, year)
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 DateStr) {
// parse m, d, y from DateStr...
// assign checks its arguments
assign(m, d, y);
}
Date::assign methodvoid Date::assign(unsigned _month,unsigned _day, unsigned _year) {
setMonth(_month);
setDay(_day);
setYear(_year);
// counter of Dates instantiated
numCreated++;
}
Direct assignment from the constructor
Rather than calling a private ‘assign’ function, the constructor could do the assignment itself.
Advantage of using ‘assign’ is the isolation of the verification process to that function.
Assignment vs. initialization in constructors
Assignment in the constructor body
Date::Date(unsigned m, unsigned d, unsigned y) {
month = m;
day = d;
year = y;
}
Assignment vs. initialization in constructors
Initialization in the initialization list
Date::Date(unsigned m, unsigned d, unsigned y) :
month(m), day(d), year(y) {};
Empty function body
Initialization list
Assignment vs. initialization in constructors
class Student {
private:
string name;
public:
Student(string aName) { name = aName; };
...
Why initialization is preferred to assignment
When a Student object is constructed, a default constructor for string name is called
Student(string aName) { string name = aName };
this allocates (1 byte of) memory inside Student::Student body, string assignment
operator is called memory is freed and allocated again
A better way of initialization
Uses initializationAvoids allocation, deallocation,
reallocation for name
Student(string aName) : name(aName) {};
Problem: Order of initialization
Initialization takes place in the order that variables were declared
Not the order in which members are in the initialization list!
Subtle dependencies possible which could cause problems (next slide)
Pitfalls of initialization listsclass my_string {
private:
char* rep;
unsigned len;
public:
my_string(const char* cp) :
len(strlen(cp)),
rep(new char[len+1]) {};Member len initialized after repBut rep uses len...
Initializing const and ref members
Assignment to constants and references prohibited
Initialization required
Const and reference members must be initialized in the constructor initialization lists
Initializing static and global objects
Few reasons to have global objectsInitialized in the order of declarationDependencies between global
objects in different filesIf you must, make them local staticInitialized when control thread first
passes over
Copy constructor
Initializes a new object from another, existing one
Signature: Class::Class(const Class&);
Copy constructor for class Date
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
Implicitly called in 3 situations defining a new object from an existing
object passing an object by value returning an object by value
Copy constructor: defining a new object
Date eosem(“12/20/1999”);
// init 2 local objects from eosem
Date eosem2(eosem);// pass by value
Date eosem3 = 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 dateDiff(Date d1, Date d2);
...
Date today;
Date eosem(12, 20, 1999);
cout << dateDiff(eosem, today);
Avoiding copy constructors
To avoid unnecessarily calling copy constructors
Do not pass object by value; pass by const ref
unsigned dateDiff(const Date& d1, const Date& d2);
Compiler-supplied copy constructor
Copies members bitwiseOK for built-in typesProblematic for resources owned by
objectSlack bytes problem
Compiler-supplied copy constructor: problems
class Date {
char* charRep; // owned by Date
...
Date today;
Date today2(today);
m:9 d:20 y:1999
charRep*
today2
m:9 d:20 y:1999
charRep*
today
9/20/1999
Shallow copy by default
The problem with the compiler supplied copy constructor is that it is a shallow copy constructor.
In the last example, both today and today2 consist of pointers set to the same block of memory.
Thus, a change to one date will affect the other.
Constructors as type conversion operators
Constructors take a single argument of a given type by value or by const reference
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 = new char[slen+1],
len(slen)
{ memset(rep, ‘ ‘, len); };
private:
char* rep;
unsigned len;
Constructors as type conversion operators
my_string s = ‘a’;
char ‘a’ is promoted to unsigned 97a string of 97 spaces is createdprobably not the desired resultKeyword explicit does not allow
implicit conversionsexplicit my_string(unsigned slen);
Destructors
Called automatically when local objects go out of scope
Called implicitly when dynamic objects are deleted
Assignment operator
Similar to the copy constructor, butRe-initializes already constructed objects
Date today; // copy constructor
...
today = “9/20/1999”;
Need assignment operator accepting char*
Assignment operator
Class Date {
Date& operator=(const char* dCptr);
...
}
Date::operator=(const char* dCptr) {
// parse dateCptr into m, d, y
assign(m, d, y);
}
Assignment operator
New C++ feature: overloading operators
Operator overloading - next lectureCompiler generates a default
assignment operator if you do not define one bitwise copy only
Assignment operator
Bitwise copy ok for classes like Date members of simple types only no pointers => no remote ownership
What happens if we bitwise copy an object owning a resource? Same problem as with default copy
constructors
Rule of Big Three
If a class has any of copy constructor destructor assignment operator
It needs all threeDestructor usually shows up firstException: when destructor only
decrements number of instances