Diferență între revizuiri ale paginii „C++ POO Lab Lucrarea 4”
Linia 210: | Linia 210: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | = | + | = Polimorfismul = |
− | Polimorfismul | + | Polimorfismul -- din greacă "poly" (mai multe) and "morphe" (forme) -- se referă la faptul că un obiect care este de tipul unei clase derivate, este în același timp și de tipul clasei de bază. Altfel spus: |
− | + | <div class="regula"><font color="#ff0000">Atenție: </font>Dacă o clasă <code>B</code> extinde (direct sau indirect) o clasă <code>A</code>, atunci un obiect <code>b</code> de tipul <code>B</code> este în același timp și de tipul <code>A</code>.</div> | |
− | + | Folosind acest concept, care este implementat și în limbajul C++, se pot utiliza pointeri sau referințe de un tip <code>T</code> pentru a referi obiecte de tipuri derivate din <code>T</code>. | |
− | |||
− | |||
− | <syntaxhighlight lang="C++"> | + | <syntaxhighlight lang="C++" line> |
− | #include < | + | #include <string> |
+ | #include <cstdio> | ||
class Animal { | class Animal { | ||
− | |||
std::string mName; | std::string mName; | ||
std::string mColor; | std::string mColor; | ||
int mAge; | int mAge; | ||
− | |||
protected: | protected: | ||
− | bool mHasFeathers; | + | bool mHasFeathers; |
public: | public: | ||
− | + | Animal(const std::string & name, const std::string & color) : mName(name), mColor(color) { | |
− | |||
} | } | ||
− | void | + | void makeSound() const { |
− | mName | + | printf("Animal %s makes a sound!\n", mName.c_str()); |
} | } | ||
// this is a getter method | // this is a getter method | ||
− | std::string getName() { | + | std::string getName() const { |
return mName; | return mName; | ||
} | } | ||
Linia 254: | Linia 250: | ||
}; | }; | ||
− | class | + | class Cat : public Animal { |
+ | unsigned int mLives; | ||
public: | public: | ||
− | + | Cat(const std::string & name, const std::string & color) : Animal(name, color), mLives(9) { | |
− | + | mHasFeathers = false; | |
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | void makeSound() const { | |
− | void | + | printf("Cat %s meows!\n", getName().c_str()); |
− | |||
− | |||
− | |||
} | } | ||
− | }; | + | }; |
int main() { | int main() { | ||
+ | Animal animal("Rex", "black"); | ||
+ | Cat cat("Spot", "tabby"); | ||
− | + | Animal & animalRef = animal; | |
− | + | Cat & catRef = cat; | |
− | Animal | + | Animal & catRef2 = cat; |
− | |||
− | + | animalRef.makeSound(); | |
− | + | catRef.makeSound(); | |
− | + | catRef2.makeSound(); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
return 0; | return 0; | ||
Linia 309: | Linia 278: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | Ieșire: | |
− | + | <syntaxhighlight lang="text"> | |
− | <syntaxhighlight> | + | Animal Rex makes a sound! |
− | + | Cat Spot meows! | |
− | Animal | + | Animal Spot makes a sound! |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Versiunea de la data 12 aprilie 2022 21:24
Această lucrare are ca scop familiarizarea cu următoarele noțiuni:
- Moștenirea
- Ascunderea metodelor
- Polimorfismul
- Metode virtuale
- Suprascrierea metodelor
- Metode pur virtuale
Moștenirea
Introducere
Moștenirea este mecanismul prin care o clasă preia structura (câmpurile) și comportamentul (metodele) unei alte (sau mai multor) clase, la care poate adăuga alți membri specifici.
Clasa de la care se preiau membrii se numește:
- clasă de bază
- superclasă
Clasa nouă, care preia membrii de la clasa de bază se numește:
- clasă derivată
- clasă extinsă
- subclasă
În C++, moștenirea poate fi multiplă, în sensul ca o clasa derivată poate moșteni mai multe clase de bază. Nu în toate limbajele există acest concept (în Java. de exemplu, există doar moștenire simplă - adică o clasă poate moșteni o singură altă clasă).
Utilitatea moștenirii în programarea orientată pe obiecte este:
- reutilizarea codului existent fără modificarea acestuia;
- extinderea a unei clase deja scrise, fără a fi necesara recompilarea ei;
- utilizarea polimorfismului în timpul execuției, prin folosirea metodelor virtuale.
Exemplu
#include <string>
#include <cstdio>
class Animal {
std::string mName;
std::string mColor;
int mAge;
protected:
bool mHasFeathers;
public:
void makeSound() const {
printf("Animal %s makes a sound!\n", mName.c_str());
}
// this is a getter method
std::string getName() const {
return mName;
}
// this is a setter method
void setAge(int age) {
if(age > 0) {
mAge = age;
}
}
};
class Cat : public Animal {
unsigned int mLives;
public:
Cat() : mLives(9) {
mHasFeathers = false;
}
};
int main() {
Cat cat;
cat.makeSound(); // makeSound este mostenita din clasa Animal
return 0;
}
În exemplul de mai sus, clasa Cat
preia toți membrii din clasa Animal
și adaugă un câmp mLives
și un constructor fără argumente. S-a introdus, de asemenea, un nou modificator de acces, protected
, care permite accesul la membrul respectiv atât din clasa curentă cât și din orice clasă derivată din clasa curentă, dar nu și din alte clase sau funcții.
Se observă, de asemenea, că moștenirea a fost declarată publică. Există două timpuri de moșteniri:
- publică
- privată
Relativ la tipul de moștenire, mai jos este prezentat modul în care se preiau membrii din clasa de bază:
Protecția in clasa de baza | Modif de acces utilizat în lista claselor de bază | Dreptul de acces în clasa derivată |
---|---|---|
public | public | public |
private | public | inaccesibil |
protected | public | protected |
public | private | private |
private | private | inaccesibil |
protected | private | private |
class
și struct
este că pentru prima, moștenirea implicită este private iar pentru a doua este public.Apelul constructorului superclasei
Când se instanțiază o clasă derivată, constructorul acestei clase se ocupă de inițializarea câmpurilor definite în clasa derivată. Pentru a inițializa câmpurile din clasa de bază, este necesar să apelăm constructorul ei. Prin urmare:
Apelul constructorului superclasei se face folosind aceeași sintaxă ca pentru inițializarea câmpurilor:
1class Animal {
2 std::string mName;
3 std::string mColor;
4 int mAge;
5protected:
6 bool mHasFeathers;
7
8public:
9 Animal(const std::string & name, const std::string & color) : mName(name), mColor(color) {
10 }
11
12 void makeSound() const {
13 printf("Animal %s makes a sound!\n", mName.c_str());
14 }
15
16 // this is a getter method
17 std::string getName() const {
18 return mName;
19 }
20
21 // this is a setter method
22 void setAge(int age) {
23 if(age > 0) {
24 mAge = age;
25 }
26 }
27};
28
29class Cat : public Animal {
30 unsigned int mLives;
31public:
32 Cat(const std::string & name, const std::string & color) : Animal(name, color), mLives(9) {
33 mHasFeathers = false;
34 }
35};
Ascunderea metodelor
În anumite situații, există nevoia ca o anumită metodă care este moștenită din clasa de bază să se comporte altfel în clasa derivată. Putem realiza acest lucru reimplementând metoda respectivă, cu aceeași semnătură, în clasa derivată. Acest mecanism se numește ascundere (hiding):
1#include <string>
2#include <cstdio>
3
4class Animal {
5 std::string mName;
6 std::string mColor;
7 int mAge;
8protected:
9 bool mHasFeathers;
10
11public:
12 Animal(const std::string & name, const std::string & color) : mName(name), mColor(color) {
13 }
14
15 void makeSound() const {
16 printf("Animal %s makes a sound!\n", mName.c_str());
17 }
18
19 // this is a getter method
20 std::string getName() const {
21 return mName;
22 }
23
24 // this is a setter method
25 void setAge(int age) {
26 if(age > 0) {
27 mAge = age;
28 }
29 }
30};
31
32class Cat : public Animal {
33 unsigned int mLives;
34public:
35 Cat(const std::string & name, const std::string & color) : Animal(name, color), mLives(9) {
36 mHasFeathers = false;
37 }
38
39 void makeSound() const {
40 printf("Cat %s meows!\n", getName().c_str());
41 }
42};
43
44int main() {
45 Animal animal("Rex", "black");
46 animal.makeSound();
47 Cat cat("Spot", "tabby");
48 cat.makeSound();
49 return 0;
50}
Ieșire:
Animal Rex makes a sound!
Cat Spot meows!
Polimorfismul
Polimorfismul -- din greacă "poly" (mai multe) and "morphe" (forme) -- se referă la faptul că un obiect care este de tipul unei clase derivate, este în același timp și de tipul clasei de bază. Altfel spus:
B
extinde (direct sau indirect) o clasă A
, atunci un obiect b
de tipul B
este în același timp și de tipul A
.Folosind acest concept, care este implementat și în limbajul C++, se pot utiliza pointeri sau referințe de un tip T
pentru a referi obiecte de tipuri derivate din T
.
1#include <string>
2#include <cstdio>
3
4class Animal {
5 std::string mName;
6 std::string mColor;
7 int mAge;
8protected:
9 bool mHasFeathers;
10
11public:
12 Animal(const std::string & name, const std::string & color) : mName(name), mColor(color) {
13 }
14
15 void makeSound() const {
16 printf("Animal %s makes a sound!\n", mName.c_str());
17 }
18
19 // this is a getter method
20 std::string getName() const {
21 return mName;
22 }
23
24 // this is a setter method
25 void setAge(int age) {
26 if(age > 0) {
27 mAge = age;
28 }
29 }
30};
31
32class Cat : public Animal {
33 unsigned int mLives;
34public:
35 Cat(const std::string & name, const std::string & color) : Animal(name, color), mLives(9) {
36 mHasFeathers = false;
37 }
38
39 void makeSound() const {
40 printf("Cat %s meows!\n", getName().c_str());
41 }
42};
43
44int main() {
45 Animal animal("Rex", "black");
46 Cat cat("Spot", "tabby");
47
48 Animal & animalRef = animal;
49 Cat & catRef = cat;
50 Animal & catRef2 = cat;
51
52 animalRef.makeSound();
53 catRef.makeSound();
54 catRef2.makeSound();
55
56 return 0;
57}
Ieșire:
Animal Rex makes a sound!
Cat Spot meows!
Animal Spot makes a sound!
Functii/Metode virtuale pure, clase abstracte
- o functie/metoda virtuala pura este o functie/metoda care nu are corp (body), nici macar gol
virtual std::string toString() {}; // nu este o functie/metoda virtuala pura, are corp
virtual std::string toString() = 0; // este o functie/metoda virtuala pura
O clasa abstracta este o clasa care contine cel putin o metoda virtuala pura, si deci nu se poate instantia (nu exista obiecte de tip clasa
Exemplu (pentru o clasa mostenita din clasa Animal de mai sus)
class Pisica : public Animal {
public:
Pisica() : Animal() // constructorul implicit Animal este chemat explicit
{
mHasFeathers = false;
} // campul mHasFeathers este protected in Animal, deci poate fi accesat de Pisica
}; // nu uitati de ; la sfarsitul unei clase