Imagine we are writing a program to manage a veterinarian's office. This veterinarian has a limited practice, only treating two kinds of pets: dogs and fish. Although this problem is unrealistically simplified and constrained, it demonstrates a program with more classes and class relationships than previous examples. A brief analysis identifies six classes connected with five relationships, as illustrated in the following UML class diagram.
The Vet example demonstrates translating a UML class diagram into C++ classes and the code implementing the relationships. The constructors and setter functions initialize the relationships and member variables. The display function demonstrates the general syntax for using the various relationships. One aspect of the association relationship is odd: The relationship is between the Owner and Pet classes, but the following program instantiates a Dog object and binds it an Owner, demonstrating the substitution of a subclass object in place of a superclass. Chapter 12 explains how substitutability benefits programs and how programmers use it to create elegant and sophisticated solutions.
#include "Owner.h"
#include "Dog.h"
using namespace std;
int main()
{
Dog myPet("Dogbert", 300);
Owner theOwner("Dilbert", "115 Elm St.", "Ogden");
myPet.setShots(2000, 9, 1); // establishes an aggregation between a Dog and a Date
myPet.setOwner(&theOwner); // establishes the Pet end of association
theOwner.setPet(&myPet); // establishes the Owner end of association
theOwner.display(); // starts a sequence of function calls displaying all program data
return 0;
}
&. Alternatively, the setShots function builds a new Date object, establishing the aggregation relationship using the function arguments.
| Owner.h | Pet.h |
|---|---|
#pragma once;
#include "Address"
#include "Pet.h"
#include <iostream>
#include <string>
using namespace std;
class Pet; // (a)
class Owner
{
private:
string name;
Pet* myPet = nullptr; // (b)
Address home; // (c)
public:
Owner(string n, string s, string c)
: name(n), home(s, c) {}
void setPet(Pet* p) { myPet = p; } // (d)
void display() // (e)
{
cout << "Owner: " << name << endl;
home.display();
if (myPet != nullptr)
myPet->display();
}
}; |
#pragma once;
#include "Owner.h"
#include <iostream>
#include <string>
using namespace std;
class Owner; // (a)
class Pet
{
private:
string name;
Owner* owner = nullptr; // (b)
public:
Pet(string n) : name(n) {}
void setOwner(Owner* o) { owner = o; } // (d)
void display() // (e)
{
cout << "Pet: " << name << endl;
}
};
|
this object. Programmers can't define functions operating on instances of forwardly declared classes in class specifications, but the restriction doesn't apply to pointers.| Dog.h | Fish.h |
|---|---|
#pragma once;
#include "Pet.h" // (a)
#include "Date.h"
#include <string>
#include <iostream>
using namespace std;
class Dog : public Pet // (b)
{
private:
int akcNum;
Date* shots = nullptr; // (i)
public:
Dog(string name, int akc)
: Pet(name), akcNum(akc) {} // (c)
~Dog() { delete shots; } // (ii)
void setShots(int y, int m, int d) // (iii)
{
if (shots != nullptr)
delete shots;
shots = new Date(y, m, d);
}
void display()
{
Pet::display(); // (d)
cout << "AKC#: " << akcNum << endl;
if (shots != nullptr)
shots->display();
}
}; |
#pragma once;
#include "Pet.h" // (a)
#include <string>
#include <iostream>
using namespace std;
class Fish : public Pet // (b)
{
private:
int color;
public:
Fish(string name, int c)
: Pet(name), color(c) {} // (c)
void display()
{
Pet::display(); // (d)
cout << "Fish color: " << color << endl;
}
};
|
| Address.h | Date.h |
|---|---|
#pragma once;
#include <string>
#include <iostream>
using namespace std;
class Address
{
private:
string street;
string city;
public:
Address(string s, string c)
: street(s), city(c) {}
void display()
{
cout << "Street: " << street <<
" City: " << city << endl;
}
};
|
#pragma once;
#include <string>
#include <iostream>
using namespace std;
class Date
{
private:
int year;
int month;
int day;
public:
Address(int y, int m, int d)
: year(m), month(m), day(d) {}
void display()
{
cout << year << "/" << month <<
"/" << day << endl;
}
};
|