SDSU CS 596 OODP
Classes: Constructors

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

Contents of Classes: Constructors Lecture

  1. Inline Function Members
    1. Classes and Files: Style Considerations
  2. Where Do I Put The Classes?
    1. Class inside of a Class
    2. Class inside of Function
  3. Initializing Class Data Members
    1. Conversion by Constructor
    2. Constructors and Destructors
    3. Stack with Constructors and Destructors
    4. Constants, Reference and Classes
    5. Constructors - initialization
    6. Static vs. Dynamic Constants
  4. Static Class Members

Inline Function Members

Method 1

class BankAccount 
{
	public:
		setBalance(float amount)	{balance = amount;} // inline
		float getBalance()		{return balance;}	// inline
		
	private:
		float balance;
};



#include <iostream.h>	

main()
{
	BankAccount me;
	
	me.setBalance(2.0);			// me.balance = 2.0

	cout << me.getBalance() << "\n";
	
}




Inline Function Members
Method 2

#include <iostream.h>

class BankAccount 
{
	public:
		void setBalance(float amount);	// OK without inline
		inline float getBalance();
		
	private:
		float balance;
};
	
inline void BankAccount::setBalance(float amount)
{
	balance = amount;
}

inline float BankAccount::getBalance()
{
	return balance;
}

main()
{
	BankAccount me;
	
	me.setBalance(2.0);
	cout << me.getBalance() << "\n";
	
}

Classes and Files: Style Considerations


Each class requires at least two files:

file for class definition
file(s) for implementation of class function members
Header file for class definition

// File:
bankAccount.hh
// Created:
Sunday, Nov. 1, 1992, 3:05 PM
// Author:
Roger Whitney
// Copyright (c)
1992 by SDSU
#ifndef
_bankAccount_HH
#define
_bankAccount_HH
#ident
"This line is used by SCCS for version control"
// Defines the interface to the BankAccount class
 
class BankAccount
{
public:
void setBalance(float amount);
float getBalance();
private:
float balance;
};
#endif
// _bankAccount_HH

Classes and Files: Style Considerations
Continued


File for class Implementation

// File:
bankAccount.cc
// Created:
Sunday, Nov. 1, 1992, 3:11 PM
// Author:
Roger Whitney
// Copyright (c)
1992 by SDSU
#ident
"This line is used by SCCS for version control"
#include
"backAccount.hh"
// Implementation of BankAccount
 

void BankAccount::setBalance(float amount)
{
balance = amount;
}
float BankAccount::getBalance()
{
return balance;
}

Classes and Files: Style Considerations
Continued


File for main program

// Standard Comment line deleted to save space
#include
"bankAccount.hh"
#include
<iostream.h>
// Sample program using bankAccount class

main()
{
BankAccount me;
me.setBalance(2.0);
cout << me.getBalance() << endl;
}

Sample makefile

test: bankAccount.o main.c
CC bankAccount.o main.cc -o test
bankAccount.o: bankAccount.hh bankAccount.cc
CC bankAccount.cc -c
clean:
rm *.o


Inline Functions and Files: Style Consideration

Do not use #define to obtain more efficient code, use inline functions

Access functions can be made inline

Use separate file to define inline functions


BankAccount.hh
class BankAccount 
{
	public:
		void setBalance(float amount);	
		float getBalance();
		
	private:
		float balance;
};


BankAccount.cc //Inline version
inline void BankAccount::setBalance(float amount)
{	balance = amount;	}

inline float BankAccount::getBalance()
{	return balance;	}

BankAccount.cc // Normal Version
void BankAccount::setBalance(float amount)
{	balance = amount;	}

float BankAccount::getBalance()
{	return balance;	}

Where Do I Put The Classes?


* Global

	As we have seen classes can be listed at the global level
	Most common


* Class

	A class can be nested inside another class
	Useful


* Local

	A class can be nested inside a function
	Rare

Class inside of a Class


#include <iostream.h>

class Outside
{
	public:
		class Inside
		{
			public:
				int chocolate;
				void taste(int it) {chocolate = it;}
		};

		int hard;
		void melt(int slow) {
				GoodStuff.taste(slow);
				hard = slow;}

	private:
		Inside GoodStuff;
}

main()
{
	Outside coating;

	Inside try;		// Legal - version 2, illegal - version 3

	Outside::Inside me;	// Legal - version 3, illegal - version 2
	
	coating.melt(5);

	cout << coating.hard << "\n";
}

Class inside of Function




myFunction(int size)
{
	class WhyInHere
	{
		public:
			int noIdea;
	};

	WhyInHere beatsMe;

	beatsMe.noIdea = size;  	// Does not do much, does it? 
}

main()
{
	myFunction(5);
}

Initializing Class Data Members


#include <iostream.h>

class BankAccount 
{
	public :		
		float balance;

		BankAccount(float amount = 0.0);
};

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

main()
{
	BankAccount A;
	BankAccount B(1.0);
	BankAccount C = 2.0;
	BankAccount D = BankAccount(3.0);
	BankAccount* E = new BankAccount(4.0);
	A = 5.0;
	B = BankAccount(6.0);
}
Output
Constuctor: 0
Constuctor: 1
Constuctor: 2
Constuctor: 3
Constuctor: 4
Constuctor: 5
Constuctor: 6

Multiple Parameters

#include <iostream.h>

class BankAccount 
{
	public :		
		float balance;

		BankAccount(float amount, int NotUsed);
};

BankAccount::BankAccount(float amount,  int NotUsed)
{
	cout << "Constuctor: " << amount << endl;
	balance = amount;
}

void main()
{
	BankAccount A(1.0, 1);
	BankAccount B = BankAccount(2.0, 2);
	BankAccount C = (3.0, 3);		// Compile Error

	A = BankAccount(4.0, 4);
	B = (4.0, 4);					// Compile Error

}

Conversion by Constructor

#include <iostream.h>

class BankAccount 
{
	public :		
		float balance;

		BankAccount(float amount, int NotUsed = 0);
};

BankAccount::BankAccount(float amount, int NotUsed)
{
	cout << "Constuctor: " << amount << endl;
	balance = amount;
}

main()
{
	BankAccount A(1.0, 2);
	A = 5.0;				// Conversion
}
Output
Constuctor: 1
Constuctor: 5

Problem
#include <iostream.h>

class BankAccount {
	public :		
		float balance;
		BankAccount(float amount );
};

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

class ThisWorksAccount {
	public :		
		float balance;
};

main()
{
	BankAccount A;	// Compile error
	ThisWorksAccount A;
}

Output
Error:   cannot find constructor for class matching BankAccount::BankAccount()

Default Constructor

The compiler generates default constructor with no arguements if there is no other constructor in the class

Constructors and Destructors

#include <iostream.h>

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

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

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

void main()
{
	BankAccount A;
	BankAccount B(1.0);
	BankAccount C = 2.0;
	BankAccount D = BankAccount(3.0);
	BankAccount* E = new BankAccount(4.0);

	A = 5.0;
}
Output
Constuctor: 0	Close out an account: 3
Constuctor: 1	Close out an account: 2
Constuctor: 2	Close out an account: 1
Constuctor: 3	Close out an account: 5
Constuctor: 4	
Constuctor: 5
Close out an account: 5

Constructors and Destructors
#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;}

void functionCallWithLocalAccount()
{	BankAccount	you(10);
	cout << "Inside Function Call\n";}
	
void main()
{	BankAccount me(5);
	
	cout << "Before function call\n";
	functionCallWithLocalAccount();
	cout << "After function call\n";}


Output
Start up an account: 5
Before function call
Start up an account: 10
Inside Function Call
Close out an account: 10
After function call
Close out an account: 5

Example Two
#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;
}

void main()
{	
	BankAccount me[5];
}

Output
Start up an account: 0
Start up an account: 0
Start up an account: 0
Start up an account: 0
Start up an account: 0
Close out an account: 0
Close out an account: 0
Close out an account: 0
Close out an account: 0
Close out an account: 0

Explain This?
#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

Stack with Constructors and Destructors


#include <iostream.h>
#include <assert.h>

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

	public:
	Stack(int StartSize = 10);	
	~Stack();
	int isEmpty() 	const;	
	int isFull()	const;		
	void push(int item);		
	float pop();				
	
private:
	float* stack;
	int nextFreeLocation;
	int size;
	void grow();
};


Stack::Stack(int StartSize)
{
	size = StartSize;
	stack = new float[StartSize];
	nextFreeLocation = 0;
}

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

Stack with Constructors and Destructors

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;
}

int Stack::isFull()	const
{
	return 0;		
}

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


Stack with Constructors and Destructors

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;
};

Modular Design Rules



Don't let a few objects run the entire show

Give each object some intelligence



Supports:

Decomposability
Composability
Continuity
Understandability


Constants, Reference and Classes




class BadNews 
{
	public:
		int 		Sam = 5;

		int&	AReference = Sam;	// Compile Error

		const int AConstant = 10;		// Compile Error

		int x;

};


Constructors - initialization


#include <iostream.h>

class ConstDataMember {
	public:
		int&	AReference;
		const int AConstant;
		int x;

		ConstDataMember(int why, int not = 13);
		friend  ostream&  operator<<(ostream&, 
					const ConstDataMember &it);
};

ConstDataMember::ConstDataMember(int why, int not) : 

	AConstant(why) , AReference(not)	// initialization phase

	{x = why + not;}; 			// assignment phase


ostream&  operator<<(ostream& output,
				 const ConstDataMember &it) {
	output 	<< it.AReference 	<< '\t'
		<< it.AConstant 	<< '\t'
		<< it.x 		<< '\t';
	return output;
};

void main() {
	ConstDataMember  Fine(7, 11);
	ConstDataMember  Well(10);
	cout << Fine << Well;
};


Constructor - Destructor Order
#include <iostream.h>

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

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

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

class Bank {
	public:
		BankAccount A;
		BankAccount B;
		BankAccount C;
		Bank();
		~Bank() { cout << "End Bank" << endl;};
};

Bank :: Bank() : B(5) { cout << "Start Bank" << endl; C = 10;};

void main() {
	Bank X;
};
Output
Constuctor: 0	Close out an account: 10
Constuctor: 5	End Bank
Constuctor: 0	Close out an account: 10
Start Bank	Close out an account: 5
Constuctor: 10	Close out an account: 0

Static vs. Dynamic Constants




main()
{
	const int	Size = 100;			// Static Constant

	int		OK[Size];			// Compiles fine
}




class NoGo 
{
	public:
		const int 	ASize;			// Dynamic Constant

		int 		NoWay[Size];		// Compile Error

		NoGo (int whyNot = 100);
};


NoGo ::NoGo (int whyNot ) : 
	ASize(why) 					// initialization phase
{}; 

 

Static Class Members


One Copy per Class

class StudentRecord
{
	public :
		char *firstName;
		static char university[10];
		static char* getUniversity();
};

char* StudentRecord::getUniversity() {
	return university;
}

char StudentRecord::university[10] = "SDSU";   

#include <iostream.h>

void main()
{
	StudentRecord me;
	StudentRecord you;

	me.firstName = "Roger";
	
	you.firstName = "Pete";

	cout << me.firstName << "\n"			// Prints Roger
		<< me.university << "\n"		// Prints SDSU
		<< StudentRecord::university << "\n"	// Prints SDSU
		<< me.getUniversity() << "\n"		// Prints SDSU
		<< StudentRecord::getUniversity();	// Prints SDSU
}

Static Class MembersThey can change value

#include <iostream.h>

class ChangeStaticMember {
	public:
		int getStatic() { return StaticNotConst; }

		void setStatic(int x) { StaticNotConst = x; }

	private:
		static int StaticNotConst;

};

int ChangeStaticMember :: StaticNotConst = 5;

void main() 
{
	ChangeStaticMember me;
	ChangeStaticMember you;

	me.setStatic(10);

	cout << me.getStatic() << endl;		// prints 10

	me.setStatic(20);

	cout << you.getStatic() << endl;		// prints 20
}
Static Members can't Access Nonstatic
class StudentRecord
{
	public :
		char *firstName;
		static char university[10];
		static char* getName();
};

char* StudentRecord::getName() {
	return firstName;				// Compile Error
}

char StudentRecord::university[10] = "SDSU";   

#include <iostream.h>

void main()
{
	StudentRecord me;
}

----------