1. Homepage of Dr. Zoltán Porkoláb
    1. Home
    2. Archive
  2. Teaching
    1. Timetable
    2. Bolyai College
    3. C++ (for mathematicians)
    4. Imperative programming (BSc)
    5. Multiparadigm programming (MSc)
    6. Programming (C in English)
    7. Programming languages (PhD)
    8. Software technology lab
    9. Theses proposals (BSc and MSc)
  3. Research
    1. CodeChecker
    2. CodeCompass
    3. Templight
    4. Projects
    5. Publications
    6. PhD students
  4. Affiliations
    1. Dept. of Programming Languages and Compilers
    2. Ericsson Hungary Ltd

Practice 20.

Inheritance and Polymorphism

Video: cpp-mat-gyak20-inheritance.mp4

This is the object-oriented version of the practice-10 when we implemented rooms and house.

person.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef PERSON_H
#define PERSON_H

class Person
{
public:
  Person(int e = 10, int c = 7, int h = 2, int m = 5);
	
  void setEnergy(int e) { energy += e; }
  void setCleanliness(int c) { cleanliness += c; }
  void setHunger(int h) { hunger += h; }
  void setMood(int m) { mood += m; }
  void printStats();
private:
  int energy;
  int cleanliness;
  int hunger;
  int mood;
};
#endif

person.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "person.h"

Person::Person(int e, int c, int h, int m)
	: energy(e), cleanliness(c), hunger(h), mood(m)
{
}
void Person::printStats()
{
  std::cout << "Energy level: " << energy << '\n';
  std::cout << "Cleanliness level: " << cleanliness << '\n';
  std::cout << "Hunger level: " << hunger << '\n';
  std::cout << "Mood level: " << mood << '\n';
  std::cout << '\n';
}

room.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef ROOM_H
#define ROOM_H

#include <string>
#include "person.h"

class Room
{
public:
  Room(float w, float l);
  virtual ~Room(){}
  float roomArea() const;
  virtual void cleanRoom(Person& p, float time);
  virtual std::string roomToString() const { return "Room"; };
  // pure virtual methods
  virtual Room* clone() const = 0;
  virtual void activity(Person& p, float time) = 0;
private:
  float width;
  float length;
  float height = 2.5;
};
#endif // ROOM_H

room.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include "room.h"

Room::Room(float w, float l)
	: width(w), length(l)
{
}
void Room::cleanRoom(Person& p, float time)
{
  std::cout << "Cleaning..." << '\n';
 
  p.setEnergy((int)(time * (-3.8))); // time * 1
  p.setCleanliness((int)(time * (-0.7)));
  p.setHunger((int)(time * 0.6));
  p.setMood((int)(time * (-3.5)));
}
float Room::roomArea() const
{
  return width * length;
}

derivedrooms.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#ifndef DERIVED_ROOMS_H
#define DERIVED_ROOMS_H

#include "room.h"

class Bedroom : public Room
{
public:
  Bedroom(float w, float l) : Room(w, l) {}
  Bedroom(const Bedroom& b) : Room(b) {}

  Bedroom* clone() const override {
                             return new Bedroom(*this); }
  void activity(Person& p, float time) override;
  std::string roomToString() const override {
                             return "Bedroom"; }
};

class Bathroom : public Room
{
public:
  Bathroom(float w, float l) : Room(w, l) {}
  Bathroom(const Bathroom& b) : Room(b) {}

  Bathroom* clone() const override { 
                           return new Bathroom(*this); }
  void activity(Person& p, float time) override;
  std::string roomToString() const override { 
                           return "Bathroom"; }
};

class Kitchen : public Room
{
public:
  Kitchen(float w, float l) : Room(w, l) {}
  Kitchen(const Kitchen& k) : Room(k) {}

  Kitchen* clone() const override { 
                           return new Kitchen(*this); }
  void activity(Person& p, float time) override;
  std::string roomToString() const override { 
                           return "Kitchen"; }
};

class LivingRoom : public Room
{
public:
  LivingRoom(float w, float l) : Room(w, l) {}
  LivingRoom(const LivingRoom& l) : Room(l) {}

  LivingRoom* clone() const { 
                       return new LivingRoom(*this); }
  void activity(Person& p, float time) override;
  std::string roomToString() const override { 
                       return "Living room"; }
};
#endif

derivedrooms.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include "derivedrooms.h"

void Bedroom::activity(Person& p, float time)
{
  std::cout << "Sleeping..." << '\n';
	
  p.setEnergy((int)time); // time * 1
  p.setCleanliness((int)(time * (-0.3)));
  p.setHunger((int)(time * 0.5));
  p.setMood((int)(time * 0.8));
}
void Bathroom::activity(Person& p, float time)
{
  std::cout << "Taking a shower..." << '\n';

  p.setEnergy((int)time * (-0.2));
  p.setCleanliness((int)(time * 1.3));  // time * 1
  p.setHunger((int)(time * 0.5));
  p.setMood((int)(time * 0.8));
}
void Kitchen::activity(Person& p, float time)
{
  std::cout << "Eating..." << '\n';

  p.setEnergy((int)time); 
  p.setCleanliness((int)(time * (-0.6)));
  p.setHunger((int)time);  // time * 1
  p.setMood((int)(time * 0.8));
}
void LivingRoom::activity(Person& p, float time)
{
  std::cout << "Watching Netflix..." << '\n';
	
  p.setEnergy((int)time * (-0.3));
  p.setCleanliness((int)(time * (-0.3)));
  p.setHunger((int)(time * 0.5));
  p.setMood((int)(time * 1.2));
}

house.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef HOUSE_H
#define HOUSE_H

#include "room.h"
#include "derivedrooms.h"
#include <vector>

class House
{
public:
  House();
  House(const std::vector<Room*>& rooms);
  House(const House& h);
  House& operator=(const House& h);
  ~House();

  int roomNumber() { return rooms.size(); }
  Room* getRoom(size_t index);
  float houseArea();
  void addRoom(Room* r);
  void printRooms();
	
private:
  std::vector<Room*> rooms;
  void copy(const House& rhs);
  void release();
};
#endif // HOUSE_H

house.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include "house.h"

House::House()
{
  addRoom(new Bedroom(3, 3));
  addRoom(new Bathroom(2, 2));
  addRoom(new Kitchen(1.5, 3));
}
House::House(const std::vector<Room*>& rooms)
{
  for (Room* room : rooms)
  {
    this->rooms.push_back(room->clone());
  }
}
House::House(const House& h)
{
  copy(h);
}
House& House::operator=(const House& h)
{
  if (this != &h)
  {
    release();
    copy(h);
  }
  return *this;
}
House::~House()
{
  release();
}
void House::copy(const House& h)
{
  for (auto room : h.rooms)
  {
    rooms.push_back(room->clone());  
  }
}
void House::release()
{
  for (auto r : rooms)
  {
    delete r;
  }
}
Room* House::getRoom(size_t index)
{
  if (index < rooms.size())
  {
    return rooms.at(index);
  }
  return nullptr;
}
float House::houseArea()
{
  float area = 0.0;   // don't forget to initialize
	
  for (auto& room : rooms)
  {
    area += room->roomArea();
  }
  return area;
}
void House::addRoom(Room* r)
{
  rooms.push_back(r);
}

void House::printRooms()
{
  for (Room* room : rooms)
  {
    std::cout << "Room type: " << room->roomToString() 
              << ", area: " << room->roomArea() << '\n';
  }
}

main.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* pointer (new, delete, nullptr), destruktor, öröklódés,
 * statikus és dinamikus típus, absztrakt osztály,
 * virtuális és tisztán virtuális metódus, overriding,
 * kovariancia és kontravariancia, többszörös öröklődés(?) */
#include <iostream>
#include "house.h"
#include "derivedrooms.h"

int main()
{
  House mansion;
  std::cout<<"Mansion area: "<< mansion.houseArea()<<'\n';

  mansion.addRoom(new LivingRoom(7.6, 6.7));
  mansion.addRoom(new Bedroom(3.8, 4.7));
  std::cout<<"Mansion area: "<< mansion.houseArea()<< '\n';
  std::cout<<"Rooms in the mansion: " << '\n';
  mansion.printRooms();
	
  std::cout << '\n';
  Person guy;
  guy.printStats();
  mansion.getRoom(2)->activity(guy, 3);

  // should have null-check
  guy.printStats();
  mansion.getRoom(0)->activity(guy, 4);
  guy.printStats();
  mansion.getRoom(1)->cleanRoom(guy, 0.5);
  guy.printStats();
  mansion.getRoom(3)->activity(guy, 7);
  guy.printStats();
  std::cout << '\n';
	
  House building = mansion;
  return 0;
}

The expected output:

$ g++ -Wall -Wextra *.cpp -o house
$ ./house 
Mansion area: 17.5
Mansion area: 86.28
Rooms in the mansion: 
Room type: Bedroom, area: 9
Room type: Bathroom, area: 4
Room type: Kitchen, area: 4.5
Room type: Living room, area: 50.92
Room type: Bedroom, area: 17.86

Energy level: 10
Cleanliness level: 7
Hunger level: 2
Mood level: 5

Eating...
Energy level: 13
Cleanliness level: 6
Hunger level: 5
Mood level: 7

Sleeping...
Energy level: 17
Cleanliness level: 5
Hunger level: 7
Mood level: 10

Cleaning...
Energy level: 16
Cleanliness level: 5
Hunger level: 7
Mood level: 9

Watching Netflix...
Energy level: 14
Cleanliness level: 3
Hunger level: 10
Mood level: 17

Financed from the financial support ELTE won from the Higher Education Restructuring Fund of the Hungarian Government.