11. Класове
Обособяване
на класове.
Ще разгледаме задача, която
се решава без използване на клас и след това с дефиниране и използване
на подходящ клас. Чете се информация за компютри, съдържаща:
Търси се продукта с най-голямо отношение оценка/цена. |
OmniBook XE
5660 76 ACMA P300 1095 75 AMAX Poewrstation 1999 78 |
int main()
{ string best_name = "";
double best_price = 0;
int best_score = 0;
bool more = true;
while (more)
{ string next_name;
double
next_price;
int next_score;
cout <<
"Please enter the model name: ";
getline(cin,
next_name);
cout <<
"Please enter the price: ";
cin >>
next_price;
cout <<
"Please enter the score: ";
cin >>
next_score;
string
remainder; /* read remainder of line */
getline(cin,
remainder);
if (next_price
!= 0)
{
if (best_price == 0 or
next_score/next_price > best_score/best_price)
{ best_name = next_name;
best_score = next_score;
best_price = next_price;
}
}
cout <<
"More data? (y/n) ";
string
answer;
getline(cin,
answer);
if (answer
!= "y") more = false;
}
cout << "The best bang
for the buck is " << best_name
<<
" (Score: " << best_score
<<
" Price: " << best_price << ")\n";
return 0;
}
Please enter the model name: OmnoBook
XE
Please enter the price: 5660 Please enter the score: 76 More data? (y/n) y Please enter the model name: Junk PC Please enter the price: 1230 Please enter the score: 51 More data? (y/n) n The best bang for the buck is Junk PC (Score: 51 Price: 1230) |
Интерфейс
и капсулиране, членове-функции.
** Второ програмно решение на задачата с използване
на класове.
// product2.cpp
#include <iostream>
#include <string>
using namespace std;
/* ДЕФИНИЦИЯ НА КЛАСА */
class Product {
public:
/* интерфейс, открита част */
/* декларации на член-функциите на класа
*/
Product();
/* създава нов продукт */
void read();
/* чете продукт */
bool is_better_than(Product
b) const;/* сравнява продукти */
void print() const;
/* отпечатва продукт */
private:
/* капсулиране, скрита част */
string name;
/* скрити данни */
double price;
/* скрити данни */
int score;
/* скрити данни */
};
/* ИЗПОЛЗВАНЕ НА КЛАСА */
int main()
{ Product best;
/* дефиниране на обект от класа */
bool more = true;
while (more)
{ Product next;
next.read();
/* извикване на член-функция на класа */
if (next.is_better_than(best))
best = next;
cout <<
"More data? (y/n) ";
string
answer;
getline(cin,
answer);
if (answer
!= "y") more = false;
}
cout << "The best bang
for the buck is ";
best.print();
/* извикване на член-функция на класа */
return 0;
}
/* РЕАЛИЗАЦИЯ НА КЛАСА */
/* дефиниция на конструктор */
Product::Product()
{ price = 10000;
score = 0;
}
/* дефиниция на член-функция мутатор (set-функция)
*/
void Product::read()
{ cout << "Please enter the
model name: ";
getline(cin, name);
cout << "Please enter
the price: ";
cin >> price;
cout << "Please enter
the score: ";
cin >> score;
string remainder;
getline(cin, remainder);
}
/* дефиниция на член-функции за достъп
(get-функция) */
bool Product::is_better_than(Product b)
const
{ if (price == 0) return false;
if (b.price == 0) return
true;
if (score/price > b.score/b.price)
return true;
return false;
}
/* дефиниция на член-функции за достъп
(get-функция) */
void Product::print() const
{ cout << name
<<
" Price: " << price
<<
" Score: " << score << "\n";
}
/* КРАЙ на файла, съдържащ текста на програмата
*/
** Неявен параметър на член-функция:
-- set-функции (мутатори) - променят (стойността
на) неявния си параметър;
void read();
-- get-функции (функции за достъп) - не променят
(стойността на) неявния си параметър, могат да се обявят като константни
функции.
void print() const;
* Полета с данни - обекти от други класове.
class Employee {
public:
Employee(string n, double
sal, int arr, int leav);
...
private:
string name;
double salary;
Time arrive;
Time leave;
};
Employee::Employee(string n, double sal,
int arr, int leav)
{ name = n;
salary = sal;
arrive = Time(arr, 0, 0);
leave = Time(leav, 0, 0);
}
Класът Employee съдържа
членове-данни, които са обекти от клас Time.
Достъп до
полетата с данни.
** Само членовете-функции имат достъп до скритите
полета с данни.
string Employee::get_name()
const
{ return name;
}
void Employee::set_salary(double
new_salary)
{ salary = new_salary;
}
** Явни и неявни параметри на функции.
Отпечатване на името и заплатата
на служител, реализирано с три различни функции:
-- член-функция с използване на достъп до скритите
данни:
void Employee::print() const
{ cout << "Name: "
<< name << " "
<< "Salary: " << salary << "\n";
}
-- член-функция с използване на член-функции
от същия клас:
void Employee::print() const
{ cout << "Name: "
<< get_name() << " "
<< "Salary: " << get_salary() << "\n";
}
-- външна за класа функция:
void print(Employee const
&emp)
{ cout << "Name: "
<< emp.get_name() << " "
<< "Salary: " << emp.get_salary() << "\n";
}
** Обособяване на класовете.
Търсят се съществителните
във формулировката на задачата - те са кандидатите за класове: играч (Player),
часовник (Clock), време (Time), игра (Game),
кръг (Round), ниво (Level).
** Определяне на интерфейс.
Определя се какви действия
трябва да бъдат извършвани с обекти от възможните класове.
* Часовникът трябва да се нарисува и да му се зададе време. |
|
* Времето трябва да може да се задава с точност до минута; да се отчитат часовете и минутите и да се сравняват показаното на часовника и отговора на играча. |
|
* Играчът има име, ниво и точки. Името и нивото му се задават в началото на играта. Точките му се увеличават по време на играта и след набиране на 5 точки се увеличава и нивото му. Ще трябва да се знае и текущото ниво на играча. |
|
* Игра:
получаване на информация за играча do { изиграване на кръг питане за продължаване на играта } while (играчът иска да продължи) |
|
** Реализиране на интерфейс.
* Клас Clock:
class Clock {
public:
Clock();
Clock(Point c, double r);
void set_time(Time t);
void draw() const;
private:
Time current_time;
Point center;
double radius;
};
void Clock::set_time(Time t)
{ current_time = t;
}
Рисуване на часовник:
- рисуване на кръг;
- рисуване на часовите деления;
- рисуване на минутните деления;
- рисуване на часовата стрелка;
- рисуване на минутната стрелка.
Рисува часово или минутно
деление:
void Clock::draw_tick(double angle, double
length) const
{ double alpha = PI/2 - 6*angle*PI/180;
Point from(center.get_x()
+ cos(alpha)*radius*(1-length),
center.get_y() + sin(alpha)*radius*(1-length));
Point to(center.get_x() +
cos(alpha)*radius,
center.get_y() + sin(alpha)*radius);
cwin << Line(from,
to);
}
Рисува стрелка:
void Clock::draw_hand(double angle, double
length) const
{ double alpha = PI/2 - 6*angle*PI/180;
Point from = center;
Point to(center.get_x() +
cos(alpha)*radius*length,
center.get_y() + sin(alpha)*radius*length);
cwin << Line(from,
to);
}
Рисува циферблат:
void Clock::draw() const
{ cwin << Circle(center, radius);
int i;
const double HOUR_TICK_LENGTH
= 0.2;
const double MINUTE_TICK_LENGTH
= 0.1;
const double HOUR_HAND_LENGTH
= 0.6;
const double MINUTE_HAND_LENGTH
= 0.75;
for (i = 0; i < 12; i++)
{ draw_tick(i * 5,
HOUR_TICK_LENGTH);
int j;
for (j
= 1; j <= 4; j++)
draw_tick(i * 5 + j, MINUTE_TICK_LENGTH);
}
draw_hand(current_time.get_minutes(),
MINUTE_HAND_LENGTH);
draw_hand((current_time.get_hours()
+
current_time.get_minutes()
/ 60.0) * 5, HOUR_HAND_LENGTH);
}
* За времето ще използваме готовия клас Time.
* Клас Player:
class Player {
public:
Player();
Player(string player_name,
int initial_level);
void increment_score();
int get_level() const;
string get_name() const;
private:
string name;
int score;
int level;
};
Player::Player(string player_name, int
initial_level)
{ name = player_name;
level = initial_level;
score = 0;
}
int Player::get_level() const
{ return level;
}
string Player::get_name() const
{ return name;
}
void Player::increment_score()
{ score++;
if (score % 5 == 0 and level
< 4) level++;
}
* Клас Game:
class Game {
public:
Game();
void play();
void read_player_information();
void play_round();
private:
Player player;
};
Game::Game()
{ rand_seed();
}
void Game::play()
{ read_player_information();
string response;
do
{ play_round();
response =
cwin.get_string("Do
you want to play again? (y/n)");
} while (response == "y");
}
void Game::read_player_information()
{ string name = cwin.get_string("What
is your name?");
int initial_level;
do
{ initial_level =
cwin.get_int("At
what level do you want to start?(1-4)");
} while (initial_level <
1 or initial_level > 4);
player = Player(name, initial_level);
}
Изиграване на кръг:
- генериране на случайно време
- показване на времето
- получаване на отговор
- ако отговорът не е правилен, отново получаване
на отговор
- ако отговорът е правилен - поздравления и увеличаване
на точките
Генериране на случайно време:
Time Game::random_time()
{ int level = player.get_level();
int minutes;
if (level == 1) minutes =
0;
else if (level == 2) minutes
= 15 * rand_int(0, 3);
else if (level == 3) minutes
= 5 * rand_int(0, 11);
else minutes = rand_int(0,
59);
int hours = rand_int(1, 12);
return Time(hours, minutes,
0);
}
Получаване на отговор:
Time Game::get_guess()
{ int hours;
do
{ hours = cwin.get_int("Please
enter hours: (1-12)");
} while (hours < 1 or
hours > 12);
int minutes;
do
{ minutes = cwin.get_int("Please
enter minutes: (0-59)");
} while (minutes < 0 or
minutes > 59);
return Time(hours, minutes,
0);
}
Изиграване на кръг:
void Game::play_round()
{ cwin.clear();
Time t = random_time();
const double CLOCK_RADIUS
= 5;
Clock clock(Point(0, 0),
CLOCK_RADIUS);
clock.set_time(t);
clock.draw();
Time guess = get_guess();
if (t.seconds_from(guess)
!= 0) guess = get_guess();
string text;
if (t.seconds_from(guess)
== 0)
{ text = "Congratulations,
" + player.get_name()
+ "! That is correct.";
player.increment_score();
}
else
text =
"Sorry, " + player.get_name()
+ "! That is not correct.";
cwin << Message(Point(-CLOCK_RADIUS,
CLOCK_RADIUS + 1),text);
}
* Главна програма:
int main()
{ Game clock_game;
clock_game.play();
return 0;
}
Цялата програма е записана
във файла clock.cpp.