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:
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:
A more advanced soultion with using inheritance and polymorphism can be found at practice-20.