## CS 596 OODP Constructors and Operators

[To Lecture Notes Index]
San Diego State University -- This page last updated Oct. 28, 1995

### Contents of Constructors and Operators Lecture

References

Lippman, C++ Primer, chapter 6
Explain This? - Symantec Compiler
```#include <iostream.h>
class BankAccount
{	public :
float balance;
BankAccount( float amount = 0.0 );
~BankAccount();};

BankAccount::BankAccount( float amount )
{	balance = amount;
cout << "Start up an account" << balance << endl;}

BankAccount::~BankAccount()
{	cout << "Close out an account"<< balance << endl;}

BankAccount nestedFunction()
{	BankAccount	you(10);
cout << "Inside nested Function\n";
return you;}

void main()
{	BankAccount me(5);

cout << "Before function call\n";
me = nestedFunction();
cout << "After function call\n";}

```
Output
```
Start up an account5
Before function call
Start up an account10
Inside nested Function
After function call
Close out an account10
Close out an account10
```

Explain This? Rohan CC
```#include <iostream.h>
class BankAccount
{	public :
float balance;
BankAccount(float amount = 0.0);
~BankAccount();};

BankAccount::BankAccount( float amount )
{	balance = amount;
cout << "Start up an account" << balance << endl;}

BankAccount::~BankAccount()
{	cout << "Close out an account"<< balance << endl;}

BankAccount nestedFunction()
{	BankAccount	you(10);
cout << "Inside nested Function\n";
return you;}

void main()
{	BankAccount me(5);

cout << "Before function call\n";
me = nestedFunction();
cout << "After function call\n";}

```
Output
```
```
Start up an account5
Before function call
Start up an account10
Inside nested Function
Close out an account10
After function call
Close out an account10
Close out an account10
The Missing Constructors!
```class BankAccount {
public :
float balance;
BankAccount( float amount = 0.0 );
BankAccount( const BankAccount& OldAccount );
~BankAccount();	};

BankAccount::BankAccount( float amount ){
cout << "Constructor: " << amount << endl;
balance = amount;}

BankAccount::BankAccount( const BankAccount& OldAccount ) {
balance = OldAccount.balance;
cout << "Copy Constructor: " << balance << endl; }

BankAccount::~BankAccount()
{	cout << "Close out an account: "<< balance << endl;}

```
BankAccount MissingCopies( BankAccount In) {
BankAccount Out( In.balance + 100 );
cout << "End Function" << endl;
return Out;}

main() {
BankAccount Start(1);
BankAccount End = MissingCopies( Start );
cout << " the end" << endl;}
Output
```Constructor: 1	Close out an account: 1
Copy Constructor: 1	 the end
Constructor: 101	Close out an account: 101
End Function	Close out an account: 1
Copy Constructor: 101
Close out an account: 101
```

## Copy Constructor - X( const X& )

The copy constructor is called in the following situations:

* Explicit initialization of one class object with another
BankAccount First( 10 );
BankAccount Second( First );
BankAccount Third = First;

* Passing of object as an argument to a function
BankAccount MissingCopies( BankAccount In )
{
BankAccount Out( In.balance + 100 );
cout << "End Function" << endl;
return Out;
}

* Return of an object in a function
BankAccount MissingCopies( BankAccount In )
{
BankAccount Out( In.balance + 100 );
cout << "End Function" << endl;
return Out;
}

But Why not just use Normal Constructors????

Constructors, Destructors and Pointers

If a class has data members which are pointers:
• The class probably needs a destructor to deallocate the pointer

```class ExamQuestion {
public :
int* data;
ExamQuestion(int amount);
~ExamQuestion();
};

ExamQuestion::ExamQuestion(int amount)
{	data = new int(amount);
}

ExamQuestion::~ExamQuestion()
{
delete data;
}
```

(to be continued)

```
class ExamQuestion
{	public :
int* data;
ExamQuestion(int amount);
~ExamQuestion();
};

ExamQuestion::ExamQuestion(int amount)
{	data = new int(amount);
cout << "Construct " << *data << endl;}

ExamQuestion::~ExamQuestion()
{	cout << "Destroy "<< *data << endl; 	 delete data;}

void TrickyPart(ExamQuestion why)
{
ExamQuestion PartA(2);		cout << "After PartA\n";
ExamQuestion PartB = why;		cout << "After PartB\n";
}

void main()
{
ExamQuestion Answer(1);		cout << "Call TrickyPart\n";

TrickyPart(Answer);			cout << "end" << endl;
}

```
Output
 Construct 1 Destroy 1 Call TrickyPart Destroy 2 Construct 2 Destroy 1 After PartA end After PartB Destroy 1

Same Example Different Details
```class Container {
public:
int value;
Container( int amount ) { value = amount };
~Container();
};

Container :: ~Container() {
cout << " You just killed: " << value << endl;
};

class ExamQuestion {
public :
Container* data;
ExamQuestion(int A) {data = new Container( A ); };
~ExamQuestion()	{  delete data;};
};

void TrickyPart(ExamQuestion why){
ExamQuestion PartB = why;		cout << "After PartB\n";
}

void main()
{
ExamQuestion Answer(1);		cout << "Call TrickyPart\n";
TrickyPart(Answer);			cout << "end" << endl;
}
```
Output
Call TrickyPart
After PartB
You just killed: 1
You just killed: 1
end You just killed: 1

### Copy Constructors Solve Pointer Problems!

```class ExamQuestion
{	public :
int* data;
ExamQuestion(int amount);
~ExamQuestion();
ExamQuestion( const ExamQuestion& );};

ExamQuestion::ExamQuestion( const ExamQuestion& Hard )
{	data = new int( *(Hard.data) + 10 );
cout << "Special " << *data << endl;}

ExamQuestion::ExamQuestion(int amount)
{	data = new int(amount);
cout << "Construct " << *data << endl;}

ExamQuestion::~ExamQuestion()
{	cout << "Destroy "<< *data << endl; 	 delete data;}

void TrickyPart(ExamQuestion why) {
ExamQuestion PartA(2);		cout << "After PartA\n";
ExamQuestion PartB = why;		cout << "After PartB\n";}

void main() {
ExamQuestion Answer(1);		cout << "Call TrickyPart\n";
TrickyPart(Answer);			cout << "end" << endl;}
```
Output
```Construct 1	After PartB
Call TrickyPart	Destroy 21
Special 11	Destroy 2
Construct 2	Destroy 11
After PartA	end
Special 21	Destroy 1
```

Constructors, Destructors and Pointers

If a class has data members which are pointers:
• The class probably needs a destructor to deallocate the pointer
• The class probably needs a copy constructor
```class ExamQuestion {
public :
int* data;
ExamQuestion(int amount);
ExamQuestion( const ExamQuestion& Copy )
~ExamQuestion();
};

ExamQuestion::ExamQuestion(int amount)
{	data = new int(amount);
}

ExamQuestion::~ExamQuestion()
{
delete data;
}
```
```ExamQuestion::ExamQuestion( const ExamQuestion& Copy )
{
data = new int( *(Copy .data)  );
}
```

(Not done yet)

### Copying - Default Copy Constructor

```#include <iostream.h>

class OK {
public:
int size;
OK( int initialSize = 10 );
~OK() {  cout << "Kill OK: " << size << endl; };
};

OK :: OK( int initialSize ) {
size = initialSize;
cout << "New OK: " << initialSize << endl;
};

class Trouble {
public:
int Location;
OK test;
Trouble( int StartValue = 5 );

};

Trouble :: Trouble(  int StartValue )	{
Location =StartValue ; test.size = 20;
};

void main() {
Trouble NotMe;
Trouble ThisIsFine = NotMe;
};

```
Output
```New OK: 10
Kill OK: 20
Kill OK: 20
```

### Copying - Implicit Call to Copy Constructor

```#include <iostream.h>

class OK {
public:
int* size;
OK( int initialSize = 10 );
OK( const OK& Copy );
~OK() {delete size; cout << "Kill OK " << *size << endl; };
};

OK :: OK( int initialSize ) {
size = new int( initialSize );
cout << "New OK: " << initialSize << endl; };

OK :: OK( const OK& Copy ) {
size = new int( *(Copy.size) );
cout << "New Copy OK: " << *size << endl; };

class Trouble {
public:
int Location;
OK test;
Trouble( int StartValue = 5 );
};

Trouble :: Trouble(  int StartValue )	{
Location =StartValue ; *(test.size) = 20;};

void main() {
Trouble NotYet;
Trouble ThisIsFine = NotYet;};

```
Output
```New OK: 10	Kill OK: 10
New Copy OK: 10	Kill OK: 10
```
Copying - Copy Constructor in Copy Constructor
```class OK {
public:
int* size;
OK( int initialSize = 10 );
OK( const OK& Copy );
~OK() {delete size; cout << "Kill OK:" << *size << endl; }; };

// See previous page for OK constructors

class Trouble {
public:
int* Location;
OK test;
Trouble( int StartValue = 5 );
Trouble( const Trouble& Copy ); };

Trouble :: Trouble(  int StartValue )	{
Location =  new int(StartValue) ; *(test.size) = 20;  };

Trouble :: Trouble(  const Trouble& Copy )	{
Location =  new int( *(Copy.Location) ) ;  };

void main() {
Trouble Now;
Trouble ThisIsIt = Now; };

```
Output
```New OK: 10	Kill OK: 10
New OK: 10	Kill OK: 20
```

Solution
```class OK {
public:
int* size;
OK( int initialSize = 10 );
OK( const OK& Copy );
~OK() {delete size; cout << "Kill OK:" << *size << endl; }; };

// See previous page for OK constructors

class Trouble {
public:
int* Location;
OK test;
Trouble( int StartValue = 5 );
Trouble( const Trouble& Copy ); };

Trouble :: Trouble(  int StartValue )	{
Location =  new int(StartValue) ; *(test.size) = 20;  };

Trouble :: Trouble(  const Trouble& Copy )	: test( Copy.test ) {
Location =  new int( *(Copy.Location) ) ;  };

void main() {
Trouble Now;
Trouble ThisIsIt = Now; };

```
Output
```New OK: 10	Kill OK: 10
New OK: 10	Kill OK: 20
```

Constructors, Destructors and Pointers

If a class has data members which are pointers:
• The class probably needs a destructor to deallocate the pointer
• The class probably needs a copy constructor
• The copy constructor should initialize the object data members in the initialization phase

```Trouble :: Trouble(  const Trouble& Copy )	: test( Copy.test ) {
Location =  new int( *(Copy.Location) ) ;  };
```

(More to Come!)

```

#include <iostream.h>

class Test
{
public:
whichOne(float a);
whichOne(int b);
};

Test::whichOne(float a)
{
cout << "In A\n";
}

Test::whichOne(int b)
{
cout << "In B\n";
}

main()
{
Test me;

me.whichOne(1.1);
me.whichOne(2);
}
```

```
#include <iostream.h>

class BankAccount
{
public :
float balance;
BankAccount(float amount = 0.0);

BankAccount& operator+(const BankAccount a);
};

BankAccount& BankAccount::operator+(const BankAccount a)
{
BankAccount *newAccount;
newAccount = new BankAccount;
newAccount->balance = balance + a.balance;
return newAccount;
}

BankAccount::BankAccount(float amount)
{
balance = amount;
}

main()
{
BankAccount me(10), you(200), us;
us = me + you;
cout << us.balance << "\n";
}

```

```

+	~	++	+=	<<=
-	!	--	-=	>>=
*	,	<<	/=	[ ]
/	=	>>	%=	( )
%	<	==	^=	->
^	>	!=	&=	->*
&	<=	&&	|=	new
|	>=	|| 	*=	delete
```
```

```
```

::	.*	.	?:

```
Can Not Create New Operators(Such is life)

### Converting User-Defined Classes via Convert Operators

```
#include <iostream.h>

class BankAccount{	public:		 float balance;			};

class WeirdStuff{
public:
operator float();
operator BankAccount() ;
};

WeirdStuff::operator float() {return 1;};

WeirdStuff::operator BankAccount() {
BankAccount* localAccount = new BankAccount;
localAccount->balance =10 ;
return *localAccount;
};

main()
{
WeirdStuff thisIs;
BankAccount What;
float a;
float b = thisIs;

a = 2 * thisIs;
What = thisIs;

cout    	<< a << "\n"            		// prints 2
<< b << "\n"            		// prints 1
<< What.balance;			// prints 10
}
```

More Conversion
```
#include <iostream.h>

class BankAccount{	public:		 float balance;			};

class WeirdStuff{
public:
operator float();
operator BankAccount() ;
};

WeirdStuff::operator float() {return 1;};

WeirdStuff::operator BankAccount() {
BankAccount* localAccount = new BankAccount;
localAccount->balance =10 ;
return *localAccount;
};

void ImplicitConversion( float argument ) {
cout << argument << endl;

};
void main()
{
WeirdStuff thisIs;
BankAccount What;
ImplicitConversion( thisIs );		// OK
ImplicitConversion( What );		// Compile Error

}
```

### Conversion by "=" operator

```#include <iostream.h>

class BankAccount{
public:
float balance;
void operator  = ( float NewValue );
};

void BankAccount :: operator  = ( float NewValue ) {
balance = NewValue;
};

void main() {
BankAccount goodCustomer;

goodCustomer.balance = 100;

goodCustomer = 200;

cout << goodCustomer.balance << endl;
};

```
Output

200

Which One is Used?
```#include <iostream.h>

class BankAccount{
public:
float balance;
BankAccount( float StartValue );
void operator  = ( float NewValue );
};

void BankAccount :: operator( float NewValue ) {
balance = NewValue;
cout << "= operator selected" << endl;
};

BankAccount :: BankAccount = ( float StartValue ) {
balance = StartValue;
cout << "Constructor selected" << endl;

};

void main() {
BankAccount goodCustomer( 100 );

goodCustomer = 200;

cout << goodCustomer.balance << endl;
};
```
Output
Constructor selected
= operator selected
200

## Review of Conversion Methods

• Convert into a class via constructor
```class BankAccount{
public:
float balance;
BankAccount( float A ) {balance = A;};
};

main() {
BankAccount test;
test = 100.0; }

```
• Convert into a class via "=" operator
```class BankAccount{
public:
float balance;
void operator  = ( float A ) {balance = A;};
};

```
• Convert out of a class via convert operator
```class BankAccount{
public:
float balance;
operator float() };

main() {
float Result
BankAccount test;
test.balance = 100.0;
Result = test;
}
```

Word to the Not So Wise

In these notes poor programming style is occasionally used:
• Public data members
• Inline functions
• No constructors
```class BankAccount{
public:
float balance;
void operator  = ( float A ) {balance = A;};
};
```

• Poor layout
```main() {
BankAccount test;
test = 100.0; }
```
• Goof ball names
class ExamQuestion

This is done mainly to keep examples to one page of 18 point text

The goofy names hopefully make it easier to sit through lectures

Assignment is not Initialization
```
class ExamQuestion
{	public :
int* data;
ExamQuestion(int amount);
ExamQuestion(const ExamQuestion&);
~ExamQuestion();
};

ExamQuestion::ExamQuestion(const ExamQuestion& Hard)
{	data = new int(*(Hard.data) +10);
cout << "Special " << *data << endl;
}

ExamQuestion::ExamQuestion(int amount)
{	data = new int(amount);
cout << "Construct " << *data << endl;
}

ExamQuestion::~ExamQuestion()
{	cout << "Destroy "<< *data << endl; 	 delete data;
}

void main()
{
ExamQuestion Start(1);
ExamQuestion Copy(2);

Copy = Start;
}
```
Output
Construct 1
Construct 2
Destroy 1
Destroy 1
Use the "=" Operator
```
class ExamQuestion  {
public :
int* data;
ExamQuestion(int amount);
ExamQuestion(const ExamQuestion&);
~ExamQuestion();
ExamQuestion& operator=(const ExamQuestion&);
};

ExamQuestion&
ExamQuestion :: operator=( const ExamQuestion& In )
{
if (this != &In) {		// beware of a = a
delete data;
data = new int( *(In.data) +15 );
cout << "= " << *data << endl;
}
return *this;
}

void main()
{
ExamQuestion Start(1);
ExamQuestion Copy(2);
Copy = Start;
}

```
Output
```Construct 1
Construct 2
= 16
end
Destroy 16
Destroy 1
```

## Constructors, Destructors and Pointers

If a class has data members which are pointers:
• The class probably needs a destructor to deallocate the pointer
• The class probably needs a copy constructor
• The copy constructor should initialize the object data members in the initialization phase
• The class probably needs an = operator to properly copy the pointers
```
```

## Stack Example Revisited

```
class Stack
{
friend ostream&  operator<<( ostream& , Stack& );

public:
Stack( int StartSize = 10 );
Stack( const Stack& );
~Stack(  );
Stack& operator=( const Stack& );

int isEmpty(  ) 	const;
int isFull(  )	const;
void push( int item );
float pop(  );

private:
float* stack;
int nextFreeLocation;
int size;

void grow(  );
void copyStack(  const Stack&  );
};

```

Stack Example Revisited - New Operations
```
void Stack :: copyStack( const Stack& oldStack )
{
size = oldStack.size;

stack = new float[size];

for ( int K = 0; K < oldStack.nextFreeLocation; K++ )
push( oldStack.stack[K] );
}

Stack :: Stack( const Stack& oldStack )
{
nextFreeLocation = 0;
size = 0;
copyStack( oldStack );
}

Stack& Stack :: operator=( const Stack& oldStack )
{
if ( this != &oldStack ) {

delete stack;
copyStack( oldStack );
}

return *this;
}
```

Stack Example Revisited - Previous Operations
```Stack :: Stack( int StartSize )
{
size = StartSize;
stack = new float[StartSize];
nextFreeLocation = 0;
}

Stack :: ~Stack(  )
{
delete stack;
}

void Stack :: grow(  )
{
float* oldStack = stack;
int oldSize = size;
size += size/2 + 1;
stack = new float[ size ];
assert( stack  != 0  );		// Why not set_new_handler?

// copy elements of old array into new

for (  int ix = 0; ix < oldSize; ++ix  )
stack[ ix ] = oldStack[ ix ];

delete oldStack;
}

int Stack :: isEmpty(  )	const
{
if ( nextFreeLocation == 0 ) return 1;
else return 0;
}

```

Stack Example Revisited - Previous Operations
```
int Stack :: isFull(  )	const
{
return 0;
}

void Stack :: push( int item )
{
if ( nextFreeLocation == size ) grow(  );
stack[nextFreeLocation++] = item;
}

float Stack :: pop(  )
{
return stack[--nextFreeLocation];
}

ostream& operator<<( ostream& output, Stack& aStack ) {
output  << "Stack( " ;

output  << aStack.stack[aStack.nextFreeLocation - 1];
for ( int K = aStack.nextFreeLocation - 2; K>= 0; K-- )
output  << "," << aStack.stack[K];

output << " )";
return output;
}

void main(  )
{
Stack books( 11 );
for ( int k = 0; k < 200; k++ )
books.push( k );
cout << books << endl;
};
```