Previous Lecture Lecture 3 Next Lecture

Lecture 3, Tue 04/10

Class Design

Classes

Example - definition of a class representing a Person

-------
# Makefile

CXX=g++

main: main.o
	${CXX} -o main -std=C++11 main.o

clean:
	rm -f *.o main
-------
// main.cpp
// Let's define the class in one file for now...

#include<iostream>
using namespace std;

// A class Person interface
class Person {
	public:
		Person(); 				// default constructor
		Person(string name, int age);
		Person(Person& person);		// copy constructor
		string getName() const; 	// accessor / getter
		int getAge() const; 		// accessor / getter
		void setName(string name); 	// mutator / setter
		void setAge(int age);		// mutator / setter

	private:
		string name;
		int age;
};

// default constructor
Person::Person() {
	name = "-";
	age = 0;
}

// constructor overloading
Person::Person(string name, int age) {
	this->name = name;
	this->age = age;
}

// copy constructor
Person::Person(Person& person) {
	name = person.getName();
	age = person.getAge();
	cout << "copy constructor" << endl;
}

string Person::getName() const { return name; }

int Person::getAge() const { return age; }

void Person::setName(string name) { this->name = name; }

void Person::setAge(int age) { this->age = age; }

int main() {
	Person p;
	return 0;
}

Public vs. Private

Abstract Data Types (ADTs):

Scope Resolution Operator

Accessor and Mutator Functions

Constructors

Copy Constructor

Shallow Copy illustration

// modify class definition with vector v
public:
vector<int>* getVector() const;

private:
vector<int>* v;

// modify constructor to initialize vector and push 100 into it
Person::Person() {
	name = "default name";
	age = 0;
	v = new vector<int>();
	v->push_back(100);
}

// Accessor function for the vector v
vector<int>* Person::getVector() const {
	return v;
}

// function to print out contents of the vector
template<class T>
void printVector(vector<T> v) {
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << endl;
	}
}


s.getVector()->push_back(200);
printVector(*s.getVector()); // 100 200
printVector(*t.getVector()); // 100 200

Vector is shared between two objects due to the shallow copy!

One way to do a “deep copy” of the vector is

Person::Person(Person& person) {
	name = person.getName();
	age = person.getAge();
	v = new vector<int>();
	
	// DEEP COPY
	for (int i = 0; i < person.getVector()->size(); i++) {
		v->push_back(person.getVector()->at(i));
	}
	cout << "copy constructor" << endl;
}

Destructor

Example of separating the Person class into multiple files

// Person.h
#ifndef PERSON_H
#define PERSON_H

#include <string>
#include <vector>

// A class interface
class Person {
	public:
		Person(); // default constructor
		Person(std::string name, int age);
		Person(Person& person);
		~Person(); 					// destructor
		std::string getName() const; 	// accessor / getter
		int getAge() const; 		// accessor / getter
		std::vector<int>* getVector() const; 
		void setName(std::string name); 	// mutator / setter
		void setAge(int age);		// mutator / setter

	private:
		std::string name;
		int age;
		std::vector<int>* v;
};

#endif
---------------------
// Person.cpp
#include <iostream>
#include "Person.h"

using namespace std;

Person::Person() {
	name = "default name";
	age = 0;
	v = new vector<int>();
	v->push_back(100);
}

Person::Person(string name, int age) {
	this->name = name;
	this->age = age;
}

Person::Person(Person& person) {
	name = person.getName();
	age = person.getAge();
	
	v = new vector<int>();
	
	// deep copy
	for (int i = 0; i < person.getVector()->size(); i++) {
		v->push_back(person.getVector()->at(i));
	}

	cout << "copy constructor" << endl;
}

Person::~Person() {
 	delete v;
 	cout << "DELETED: v" << endl;
 }

vector<int>* Person::getVector() const {
	return v;
}

string Person::getName() const {
	return name;
}

int Person::getAge() const {
	return age;
}

void Person::setName(string name) {
	this->name = name;
}

void Person::setAge(int age) {
	this->age = age;
}
-------------
// main.cpp

#include <iostream>
#include "Person.h"

using namespace std;

template<class T>
void printVector(vector<T> v) {
	for (int i = 0; i < v.size(); i++) {
		cout << v[i] << endl;
	}
}

// just illustrating destructor gets called when out of scope…
void f() {
	Person* p = new Person();
	delete p;
}

int main() {
	f();
	cout << "exiting main..." << endl;
	return 0;
}
----
# Makefile

CXX=g++

main: main.o Person.o
	${CXX} -o main -std=C++11 main.o Person.o

clean:
	rm -f *.o main

Note: You should not use using namespace ... in your header files. This can have unintended side-effects for consumers of this class that are not expecting to use the namespace.