3. Класове

  В лекциите до тук за класовете са разгледани:
- конструиране на обект: Employee harry("Hacher, Harry", 350);
- модифициране на обект: harry.set_salary(380);
- извеждане на информация за обект: cout << harry.get_name();
Въведени са и основните понятия конструктор, член-функция и операция точка.


Обособяване на класове.
Ще разгледаме задача, която се решава без използване на клас и след това с дефиниране и използване на подходящ клас. Чете се информация за компютри, съдържаща:
име на модел name OmniBook XE
цена price 5660
оценка score 76
OmniBook XE
5660
76
ACMA P300
1095
75
AMAX Poewrstation
1999
78
Търси се продукта с най-голямо отношение оценка/цена.
** Първото програмно решение е без използване на класове.
// bestval.cpp
#include <iostream>
#include <string>
using namespace std;

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;  



Разделяне програмата на:
-- заглавен файл (product.h),
-- дефиниции на фукциите на класа (product.cpp
-- използване на обекти от класа (prodtest.cpp)
Разделна компилация.


Конструктори по подразбиране и с параметри.
** Конструкторът инициализира (задава начални стойности на) данните на класа. Няма тип и не връща стойност.
** Предефиниране на функции - две функции в една програма на С++ могат да имат еднакви имена. За да бъдат различими, те трябва да имат различен брой параметри или/и параметрите им да са от различен тип.
class Employee {
public:
/* конструктор без параметри */
   Employee();
/* конструктор с параметри */
   Employee(string emp_name, double init_salary);
   void set_salary(double new_salary);
   string get_name() const;
   double get_salary() const;
   void print() const;
private:
   string name;
   double salary;
};
/* дефиниция на канструктора с параметри */
Employee::Employee(string emp_name, double init_salary)
{ name = emp_name;
  salary = init_salary;  }

* Полета с данни - обекти от други класове.
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(const Employee &emp)
   { cout << "Name: " << emp.get_name() << "    "
          << "Salary: " << emp.get_salary() << "\n";
   }
Пример:

// employee.cpp
#include <iostream>

using namespace std;
#include <ccc_time.h>

class Employee {
public:
   Employee(string employee_name, double initial_salary,
            int arrive_hour, int leave_hour);

   void set_salary(double new_salary);
   void raise_salary(double percent);

   string get_name() const;
   double get_salary() const;
   void print() const;
private:
   string name;
   double salary;
   Time arrive;
   Time leave;
};

Employee::Employee(string employee_name, double initial_salary,
   int arrive_hour, int leave_hour)
{  name = employee_name;
   salary = initial_salary;
   arrive = Time(arrive_hour, 0, 0);
   leave = Time(leave_hour, 0, 0);
}

void Employee::set_salary(double new_salary)
{  salary = new_salary; 
}    

string Employee::get_name() const
{  return name;
}

double Employee::get_salary() const
{  return salary;
}

void Employee::raise_salary(double percent)
{  salary = salary * (1 + percent / 100);
}

void raise_salary(Employee& e, double percent)
{  double new_salary = e.get_salary() * (1 + percent / 100);
   e.set_salary(new_salary);
}

void Employee::print() const
{  cout << "Name: " << get_name() << "; "
        << "Salary: " << get_salary()
        << "\n";
}

int main()
{ Employee harry("Harry", 1000, 8, 16);
  harry.raise_salary(10);
  harry.print();
  raise_salary(harry, 10);
  cout << "New salary " << harry.get_salary() << endl;
  return 0;  
}   


Използване на указатели в класове
**Пример (optional attribute): Ако някой департамент има администратор, то указател ще сочи към този онект, ако не - указателят ще има стойност NULL

class Department {
. . .
private:
string name;
Employee* receptionist;
};

**Пример (sharing): Някои департаменти могат да имат администратор и/или секретар, като някъде един и същи служител може да заема и двете длъжности.

class Department {
. . .
private:
string name;
Employee* receptionist;
Employee* secretary;
};

Ето и цяла програма:
// department.cpp
#include
<string> #include <iostream> using namespace std; #include "ccc_empl.h" /**
A department in an organization. */ class Department { public: Department(string n); void set_receptionist(Employee* e); void set_secretary(Employee* e); void print() const; private: string name; Employee* receptionist; Employee* secretary; }; /** Constructs a department with a given name. @param n the department name */ Department::Department(string n) { name = n; receptionist = NULL; secretary = NULL; } /** Sets the receptionist for this department. @param e the receptionist */ void Department::set_receptionist(Employee* e) { receptionist = e; } /** Sets the secretary for this department. @param e the secretary */ void Department::set_secretary(Employee* e) { secretary = e; } /** Prints a description of this department. */ void Department::print() const { cout << "Name: " << name << "\n" << "Receptionist: "; if (receptionist == NULL) cout << "None"; else cout << receptionist->get_name() << " " << receptionist->get_salary(); cout << "\nSecretary: "; if (secretary == NULL) cout << "None"; else if (secretary == receptionist) cout << "Same"; else cout << secretary->get_name() << " " << secretary->get_salary();
cout << "\n"; } int main() { Department shipping("Shipping"); Department qc("Quality Control"); Employee* harry = new Employee("Hacker, Harry", 45000); shipping.set_secretary(harry); Employee* tina = new Employee("Tester, Tina", 50000); qc.set_receptionist(tina); qc.set_secretary(tina); tina->set_salary(55000); shipping.print(); qc.print(); return 0; }