Jak dotądDo tej pory używaliśmy korzystaliśmy z pojedynczego i wielokrotnego dziedziczenia pojedynczego i wielokrotnego w celu stworzenia relacji typu jest-czymś.
W Z tegotym rozdzialełu dowiesz się:
· Cczym jest zawieranie i jak je zamodelować,.
· Cczym jest delegowanie i jak je zamodelować,.
· Jjak zaimplementować daną klasę poprzez inną,.
· Jjak używać dziedziczenia prywatnego dziedziczenia.
Jak widzieliśmy pokazaliśmy w poprzednich przykładach, możliwe jest, by dane składowe jednej klasy obejmowały obiekty innych klas. Programiści C++ mówią wtedy, że klasa zewnętrzna zawiera klasę wewnętrzną. Tak więc klasa Employee (pracownik) może zawierać na przykład obiekt typu łańcucha (przechowujący nazwisko pracownika) oraz składowe całkowite (zawierające jego pensję i inne dane).
Listing 16.1 opisuje niekompletną, choć wciążjednakowoż użyteczną klasę String, dość podobną do klasy String zadeklarowanej w rozdziale 13. Ten listing nie dajegeneruje żadnego wynikuwydruku. Zamiast tego zostanieBędzie on jednak wykorzystanywany razem z dalszymi listingami.
Listing 16.1. Klasa String
0: // Listing 16.1 Klasa String
1:
2: #include <iostream>
3: #include <string.h>
4: using namespace std;
5:
6: class String
7: {
8: public:
9: // konstruktory
10: String();
11: String(const char *const);
12: String(const String &);
13: ~String();
14:
15: // przeciążone operatory
16: char & operator[](int offset);
17: char operator[](int offset) const;
18: String operator+(const String&);
19: void operator+=(const String&);
20: String & operator= (const String &),
21:
22: // ogólne akcesory
23: int GetLen()const { return itsLen; }
24: const char * GetString() const { return itsString; }
25: static int ConstructorCount;
26:
27: private:
28: String (int); // prywatny konstruktor
29: char * itsString;
30: unsigned short itsLen;
31:
32: };
33:
34: // domyślny konstruktor tworzący ciąg pusty (zera0 bajtów)
35: String::String()
36: {
37: itsString = new char[1];
38: itsString[0] = '\0';
39: itsLen=0;
40: // cout << "\tDomyslny konstruktor lancucha\n";
41: // ConstructorCount++;
42: }
43:
44: // prywatny (pomocniczy) konstruktor, używany tylko przez
45: // metody klasy przy tworzeniu nowego, wypełnionego zerowymi
46: // bajtami, łańcucha o zadanej długości
47: String::String(int len)
48: {
49: itsString = new char[len+1];
50: for (int i = 0; i<=len; i++)
51: itsString[i] = '\0';
52: itsLen=len;
53: // cout << "\tKonstruktor String(int)\n";
54: // ConstructorCount++;
55: }
56:
57: // Zamienia tablice znaków w typ String
58: String::String(const char * const cString)
59: {
60: itsLen = strlen(cString);
61: itsString = new char[itsLen+1];
62: for (int i = 0; i<itsLen; i++)
63: itsString[i] = cString[i];
64: itsString[itsLen]='\0';
65: // cout << "\tKonstruktor String(char*)\n";
66: // ConstructorCount++;
67: }
68:
69: // konstruktor kopiującyi
70: String::String (const String & rhs)
71: {
72: itsLen=rhs.GetLen();
73: itsString = new char[itsLen+1];
74: for (int i = 0; i<itsLen;i++)
75: itsString[i] = rhs[i];
76: itsString[itsLen] = '\0';
77: // cout << "\tKonstruktor String(String&)\n";
78: // ConstructorCount++;
79: }
80:
81: // destruktor, zwalnia zaalokowaną pamięć
82: String::~String ()
83: {
84: delete [] itsString;
85: itsLen = 0;
86: // cout << "\tDestruktor klasy String\n";
87: }
88:
89: // operator równości, zwalnia istniejącą pamięć,
90: // po czym kopiuje łańcuch i rozmiar
91: String& String::operator=(const String & rhs)
92: {
93: if (this == &rhs)
94: return *this;
95: delete [] itsString;
96: itsLen=rhs.GetLen();
97: itsString = new char[itsLen+1];
98: for (int i = 0; i<itsLen;i++)
99: itsString[i] = rhs[i];
100: itsString[itsLen] = '\0';
101: return *this;
102: // cout << "\toperator= klasy String\n";
103: }
104:
105: //nie const operator indeksu, zwraca
106: // referencję do znaku, więc można go
107: // zmienić!
108: char & String::operator[](int offset)
109: {
110: if (offset > itsLen)
111: return itsString[itsLen-1];
112: else
113: return itsString[offset];
114: }
115:
116: // const operator indeksu do używania z obiektami
117: // const (patrz konstruktor kopiującyi!)
118: char String::operator[](int offset) const
119: {
120: if (offset > itsLen)
121: return itsString[itsLen-1];
122: else
123: return itsString[offset];
124: }
125:
126: // tworzy nowy łańcuch przez dodanie do rhs
127: // bieżącego łańcucha
128: String String::operator+(const String& rhs)
129: {
130: int totalLen = itsLen + rhs.GetLen();
131: String temp(totalLen);
132: int i, j;
133: for (i = 0; i<itsLen; i++)
134: temp[i] = itsString[i];
135: for (j = 0; j<rhs.GetLen(); j++, i++)
136: temp[i] = rhs[j];
137: temp[totalLen]='\0';
138: return temp;
139: }
140:
141: // zmienia bieżący łańcuch, nie zwraca nic
142: void String::operator+=(const String& rhs)
143: {
144: unsigned short rhsLen = rhs.GetLen();
145: unsigned short totalLen = itsLen + rhsLen;
146: String temp(totalLen);
147: int i, j;
148: for (i = 0; i<itsLen; i++)
149: temp[i] = itsString[i];
150: for (j = 0; j<rhs.GetLen(); j++, i++)
151: temp[i] = rhs[i-itsLen];
152: temp[totalLen]='\0';
153: *this = temp;
154: }
155:
156: // int String::ConstructorCount = 0;
UWAGA Umieść Kkod z listingu 16.1 umieść w pliku o nazwie String.hpp. Wtedy zZa każdym razem, gdy będziesz potrzebował klasy String, będziesz mógł dołączyć listing 16.1 (używając instrukcji #include "String.hpp";, tak jak to robimy w dalszych listingach przedstawionych w tym rozdziale).
Wynik:
Brak
Analiza:
Listing 16.1 zawiera klasę String, bardzo podobną do klasy String z listingu 13.12 przedstawionego w rozdziale trzynastym, „Tablice i listy połączone”. Najważniejszą różnicą jest to, żeJednakże konstruktory i inne funkcje z listingu 13.12 zawierały instrukcje wypisujące na ekranie komunikaty na ekranie; w listingu 16.1 instrukcje te zostały wykomentowane. Z funkcji tych skorzystamy w następnych przykładach.
W linii 25. została zadeklarowana statyczna zmienna składowa ConstructorCount (licznik konstruktorów), która jest inicjalizowana w linii 156. Ta zmienna jestpodlega inkrementacji inicjalizowana w każdym konstruktorze klasy. Wszystko to zostało na razie wykomentowane; skorzystamy z tego dopiero w następnych listingach.
Listing 16.2 przedstawia klasę Employee (pracownik), zawierającą trzy obiekty typu String.
Listing 16.2. Klasa Employee i program sterujący
0: // Listing 16.2 Klasa Employee i program sterujący
1: #include "String.hpp"
2:
3: class Employee
4: {
5: public:
6: Employee();
7: Employee(char *, char *, char *, long);
8: ~Employee();
9: Employee(const Employee&);
10: Employee & operator= (const Employee &);
11:
12: const String & GetFirstName() const
13: { return itsFirstName; }
14: const String & GetLastName() const { return itsLastName; }
15: const String & GetAddress() const { return itsAddress; }
16: long GetSalary() const { return itsSalary; }
17:
18: void SetFirstName(const String & fName)
19: { itsFirstName = fName; }
20: void SetLastName(const String & lName)
21: { itsLastName = lName; }
22: void SetAddress(const String & address)
23: { itsAddress = address; }
24: void SetSalary(long salary) { itsSalary = salary; }
25: private:
26: String itsFirstName;
27: String itsLastName;
28: String itsAddress;
29: long itsSalary;
30: };
32: Employee::Employee():
33: itsFirstName(""),
34: itsLastName(""),
35: itsAddress(""),
36: itsSalary(0)
37: {}
38:
39: Employee::Employee(char * firstName, char * lastName,
40: char * address, long salary):
41: itsFirstName(firstName),
42: itsLastName(lastName),
43: itsAddress(address),
44: itsSalary(salary)
45: {}
46:
47: Employee::Employee(const Employee & rhs):
48: itsFirstName(rhs.GetFirstName()),
49: itsLastName(rhs.GetLastName()),
50: itsAddress(rhs.GetAddress()),
51: itsSalary(rhs.GetSalary())
52: {}
53:
54: Employee::~Employee() {}
55:
56: Employee & Employee::operator= (const Employee & rhs)
57: {
58: if (this == &rhs)
...
kamil6966