Você está na página 1de 56

Constructors and

Destructors


Outline
Constructors 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 class
Are called automatically when class object
declared
Initialize (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 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
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& DateStr);

When do constructors get
called?
Block local (automatic) object
Dynamically allocated object
Class argument passed by value
Class object returned by value
Class member that is an object
Array element
Temporary object
Local static object
Global 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, or
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 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 initialized
Do 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 one
BankAccount 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
objects
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
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
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 eoq2(eoq);
Common tasks of
overloaded constructors
Checking arguments
Incrementing the number of instances
All 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 method
void 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 initialization
Avoids 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 lists
class 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 rep
But 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 objects
Initialized in the order of declaration
Dependencies between global objects in
different files
If you must, make them local static
Initialized 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 bitwise
OK for built-in types
Problematic for resources owned by
object
Slack 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 97
a string of 97 spaces is created
probably not the desired result
Keyword explicit does not allow
implicit conversions
explicit 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, but
Re-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 lecture
Compiler 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 three
Destructor usually shows up first
Exception: when destructor only
decrements number of instances

Você também pode gostar