Anropsordningen för konstruktorer och destruktorer i samband med arv och komposition

Följande är ett exempel på ett litet objektorienterat program bestående av tre klasser; Date, Person och Employee vilka är relaterade till varandra enligt följande.

Prova att stepa igenom programmet sats för sats med debuggerns trace funktion genom att ladda ner kodfilerna employee.h och employee.cpp. Kontrollera att du förstår hur reglerna för konstruktorernas och destruktorernas anropsordning.

När man skapar ett objekt sker följande:

  1. Konstruktorn för en eventuell basklass (överklass) anropas alltid först.
  2. Konstruktorer för den egna klassens datamedlemmar anropas och initieras (i den ordning de räknas upp i initieringslistan).
  3. Satserna i den egna klassens konstruktor exekveras.
När man tar bort ett objekt sker följande:
  1. Satserna i den egna destruktorn exekveras.
  2. Destruktorerna för den egna klassens datamedlemmar anropas.
  3. Den eventuella basklassens destruktor anropas.

Filen: employee.h

#ifndef EMPLOYEE_H
#define EMPLOYEE_H

//
// Date
//
class Date
{
friend ostream & operator << (ostream &, const Date &);
public:
	Date(int, int, int);
	~Date();
private:
	int year;
	int month;
	int day;
};

//
// Person
//
class Person
{
friend ostream & operator << (ostream &, const Person &);
public:
	Person(char * = "", int y = 1990, int m = 1, int d = 1);
	Person(const Person &);
	~Person();
	const Person & operator = (const Person &);
private:
	char * name;
	Date birth;			// Komposition
};

//
// Employee
//
class Employee : public Person
{
friend ostream & operator << (ostream &, const Employee &);
public:
	Employee();
	Employee(char *, int, int, int, int);
	~Employee();
	void print();
private:
	int salary;
};

#endif

Filen: employee.cpp

#include <string.h>
#include <iostream.h>
#include <iomanip.h>

#include "employee.h"

// Konstruktor
Date::Date(int y, int m, int d)
{
	year = y;
	month = m;
	day = d;
}

// Destruktor
Date::~Date()
{
	// Destruktorn finns bara implementerad för att visa när den anropas...
}

// Vänfunktion (överlagring av utskriftsoperatorn för Date-objekt)
ostream & operator << (ostream & os, const Date & date)
{
	os << setw(4) << setfill(' ') << date.year << '-';
	os << setw(2) << setfill('0') << date.month << '-';
	os << setw(2) << setfill('0') << date.day;
	return os;
}

// Konstruktor
Person::Person(char * n, int y, int m, int d) : birth(y, m, d)
{
	name = new char[strlen(n) + 1];
	strcpy(name, n);
}

// Kopieringskonstruktor
Person::Person(const Person & person) : birth(person.birth)
{
//	birth = person.birth;
	name = new char[strlen(person.name) + 1];
	strcpy(name, person.name);
}

// Tilldelningsoperator
const Person & Person::operator = (const Person & person)
{
	if (this != &person)
	{
		birth = person.birth;
		delete [] name;
		name = new char[strlen(person.name) + 1];
		strcpy(name, person.name);
	}
	return *this;
}

// Destruktor
Person::~Person()
{
	delete [] name;
}

// Vänfunktion (överlagring av utskriftsoperatorn för Person-objekt)
ostream & operator << (ostream & os, const Person & person)
{
	os << person.name << "  " << person.birth << "-XXXX";
	return os;
}

// Konstruktor
Employee::Employee() : Person("", 1990, 1, 1), salary(0)
{
}

// Konstruktor
Employee::Employee(char * n, int y, int m, int d, int s) : Person(n, y, m, d)
{
	salary = s;
}

// Destruktor
Employee::~Employee()
{
	// Destruktorn finns bara implementerad för att visa när den anropas...
}

// Vänfunktion (överlagring av utskriftsoperatorn för Employee-objekt)
ostream & operator << (ostream & os, const Employee & employee)
{
	os << Person(employee) << " : " << employee.salary << " kr";
	return os;
}

int main(void)
{
	Employee p1("Arne Anka", 1963, 4, 2, 12500);
	Employee p2("Nalle Phu", 1958,11,30, 27200);

	cout << p1 << endl;
	cout << p2 << endl;

	Employee p3 = p1;			// Initiering

	Employee p4;
	p4 = p2;				// Tilldelning

	cout << p3 << endl;
	cout << p4 << endl;

	return 0;
}