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 (MSc Aut. Sys.)
    7. Programming languages (PhD)
    8. Software technology lab
    9. Theses proposals (BSc and MSc)
  3. Research
    1. Sustrainability
    2. CodeChecker
    3. CodeCompass
    4. Templight
    5. Projects
    6. Conferences
    7. Publications
    8. PhD students
  4. Affiliations
    1. Dept. of Programming Languages and Compilers
    2. Ericsson Hungary Ltd

Practice 10.

Room, Houses and Classes

In the lecture 13 we learned classes as the basic element of Object-oriented programming. In ths practice we will make a small system with houses and rooms as a sample of the use and creation of classes.

Please, be aware, that here we will use enum class to represent the type of the rooms with enumeration values.

  • First, in enum class the class keyword is only for syntactical purposes; an enum class is just a colelction of names constants, nothing about classes.

  • Second, in real object oriented programs it is better to avoid the use of enums or enum classes as type selectors. The good solution is the use of inheritance that we will learn later (see practice-20 ).

Solution

Video:

cpp-mat-gyak10-classes.mp4

We will represent the rooms with the Room class. The interface of the Room class is placed into the room.h header file.

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
#ifndef ROOM_H
#define ROOM_H

#include <string>

enum class RoomType   // type selector for the "kind" of room
{
  BED,
  BATH,
  KITCHEN,
  LIVING
};

class Room
{
public:
  Room(float w, float l, RoomType t);
  
  float roomArea();
  RoomType getType() { return type; }
  std::string roomTypeToString(RoomType t);
	
private:
  float width;
  float length;
  float height = 2.5;  // in class initialization:
	               // all Rooms will be 2.5 high
  RoomType type;
};

#endif

The implementation is written in the room.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
#include "room.h"
#include <map>

namespace  // implementation detail, 
{           // not visible outside of this file

  // mapping the "Room kind" to printable string
  std::map<RoomType, std::string> types =
  {
    std::make_pair(RoomType::BED, "Bedroom"),
    std::make_pair(RoomType::BATH, "Bathroom"),
    std::make_pair(RoomType::KITCHEN, "Kitchen"),
    std::make_pair(RoomType::LIVING, "Living room")
  };
}
Room::Room(float w, float l, RoomType t)
   : width(w), length(l), type(t)   // initialization list
{
}
/*
// other (but less favorable way) to initialize the fields
Room(float w, float l, RoomType t)
{
  this->width = w;  // this->  is not necessary here
  this->length = l; // length is this->length, if not  
  this->type = t;   // hdden by parameter or local variable
}
*/
float Room::roomArea()
{
  return width * length;
}
std::string Room::roomTypeToString(RoomType t)
{
  return types[t]; // for map: return the value with key "t"
}

The interface of the House class is written to house.h. Consider the overloaded constructors.

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

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

class House
{
public:
  House();   // default constructor == no parameter
  House(std::vector<Room> rooms);
	
  void addRoom(float w, float l, RoomType t);
  bool demolishRoom(RoomType t);
	
  size_t roomNumber() { return rooms.size(); }
  float houseArea();
  void printRooms();
private:
  std::vector<Room> rooms;
};
#endif

The implementation of the House class is placed into house.cpp source file.

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
#include <iostream>
#include "house.h"

House::House()
{
  addRoom(3, 3, RoomType::BED);
  addRoom(2, 2, RoomType::BATH);
  addRoom(1.5, 3, RoomType::KITCHEN);
}
House::House(std::vector<Room> rooms)
{
  for (const Room& room : rooms)
  {
    // "this->" is necessary here, since the "rooms" field 
    // is hidden by the "rooms" parameter of the constructor
    this->rooms.push_back(room); 
  }                        
  // other way to do since C++11
  // this->rooms = std::move(rooms);
}
void House::addRoom(float w, float l, RoomType t)
{
  rooms.push_back(Room(w, l, t));
}
// demolishes the first room of type t
bool House::demolishRoom(RoomType t)
{
  for (auto it = rooms.begin(); it != rooms.end(); ++it)
  {
    if (it->getType() == t)
    {
      rooms.erase(it); // iterator "it" invalidated here!
      return true;
    }
  }
  return false;  // not found room of "t" kind 
}

The main program to create houses:

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
#include <iostream>
#include "house.h"

int main()
{
  House mansion;
  std::cout << mansion.roomNumber() << std::endl;
  std::cout << "Mansion area: " << mansion.houseArea() 
                                << std::endl;
  mansion.printRooms();
  std::cout << std::endl;
	
  mansion.addRoom(7.6, 6.7, RoomType::LIVING);
  std::cout << mansion.roomNumber() << std::endl;
  std::cout << "Mansion area: " << mansion.houseArea() 
                                << std::endl;
  mansion.printRooms();
	
  mansion.demolishRoom(RoomType::BED);
  mansion.printRooms();
  std::cout << std::endl;
	
  std::vector<Room> rooms = 
  {
    {3, 3, RoomType::BED},
    {2, 4, RoomType::BATH},
    {1.5, 6, RoomType::KITCHEN}
  };
  House manor(rooms);
  manor.printRooms();
  return 0;
}

The program is compiled with all source files and linked together. The expected output is the following:

$ g++ -Wall -Wextra room.cpp house.cpp main.cpp -o houses
$ ./houses 
3
Mansion area: 17.5
Room type: Bedroom, area: 9
Room type: Bathroom, area: 4
Room type: Kitchen, area: 4.5

4
Mansion area: 68.42
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: Bathroom, area: 4
Room type: Kitchen, area: 4.5
Room type: Living room, area: 50.92

Room type: Bedroom, area: 9
Room type: Bathroom, area: 8
Room type: Kitchen, area: 9

A more advanced soultion with using inheritance and polymorphism can be found at practice-20.


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