БлогNot. C++: пишем маленькие классы

Помощь дата->рейтинг Поиск Почта RSS канал Статистика nickolay.info Домой

C++: пишем маленькие классы

Просто несколько учебных примеров на классы под общим лозунгом "КРТКСТ - СТ".

1. Переопределение операторов - удобная и красивая вещь, на неё в блоге есть и теория, и примеры. Тем не менее, вот ещё один маленький пример - научим программу складывать объекты класса c.

В простых случаях достаточно, чтобы переопределённый оператор возвращал новый объект класса, тогда будет работать и сложение "по цепочке" вида a+b+... Аргумент слева от знака "+" доступен через указатель this, справа - через ссылочный аргумент оператора b:

#include <iostream>
#include <cstring>
using namespace std;
/* Бинарный "+", работающий по цепочке */
class c {
public:
    double val;
    c(double val=0);
    c operator + (c &);
};
c::c(double val) { this->val=val; }
c c::operator +(c &b) {
 c *d=new c(this->val+b.val); return *d;
}

int main(void) {
 c a(1),b(2),d(3);
 c *e=new c(); *e=a+b+d; cout << e->val;
 c f; f = a+b+d; cout << endl << f.val;
 system("pause"); return 0;
}

Правильные теоретики также часто рекомендуют делать для бинарных операторов дружественные функции:

friend c operator + (const c & a, const c & b); //прототип в классе

c operator + (const c& a, const c& b) { //реализация
 return c (a.x + b.x);
}

2. Класс "Человек" с условием задачи:

Чтобы не заморачиваться с получением текущего года из <ctime>, сделаем его статическим членом класса, который, как положено, инициализируем вне всех функций и до main. Оператор "<" определим дважды, для возможности сравнения как с целым числом, так и с возрастом, взятым из другого экземпляра класса.

#include <iostream>
#include <string>
using namespace std;
/* Вариант 5. Класс "Человек" */
class c {
 string name; int age; //имя и год рождения
public:
 static int year; //статическое св-во "текущий год"
 void show(); //показать информацию
 int getAge(); //показать возраст в годах
 c (string name=0,int age=0);
 c & operator += (string); //переопределить имя
 bool operator < (int); //достиг ли возраст значения
 bool operator < (c &); //сравнение возрастов 2 людей
};
int c::year=2017;
void c::show() { cout << endl << name << "," << age; }
int c::getAge() { return year-age+1; }
c::c (string name,int age) {this->name=name; this->age=age; }
c & c::operator += (string b) {
 this->name = b; return *this;
}
bool c::operator < (int b) { return getAge()<=b; }
bool c::operator < (c &b) { return this->getAge()<b.getAge(); }

int main(void) {
 c a("Ivanov",1980); a.show();
 string s("Petrov"); a+=s; a.show();
 bool b=a<30;
 cout << endl << (b ? "1" : "0");
 c a2("Popov",1990); a2.show();
 b=a<a2;
 cout << endl << (b ? "a<a2" : "a>=a2");
 cout << endl; system("pause"); return 0;
}

3. Класс "Стек из целых чисел" с условем задачи:

Для удобства добавим в стек ещё и свойство "текущее количество элементов" current.

Если элемент нельзя положить в стек из-за заполненности, не будем делать ничего (хотя можно было что-то возвращать из метода push).

Если элемент нельзя извлечь потому, что стек пуст, будем возвращать INT_MAX.

Тогда реализация окажется простой.

#include <iostream>
#include <string>
#include <climits>
using namespace std;
class c {
 int size; //размер
 int *items; //элементы
 int current; //текущая позиция
public:
 void push(int); //положить элемент
 int pop(); //взять элемент
 c (int size=2);
 int operator !(void); //текущая емкость
};
c::c(int size) { this->size=size; current=0;
 items = new int[size];                     }
int c::operator !(void) { return current; }
void c::push(int item) {
 if (current<size) items[current++]=item;
}
int c::pop(void) {
 return current>0 ? items[--current] : INT_MAX;
}

int main(void) {
 c a(3);
 a.push(1); a.push(2); a.push(3);
 a.push(4); //уже не добавится
 cout << a.pop() << "," << a.pop() << "," << a.pop(); //!!!
 cout << endl << !a;
 cout << endl; system("pause"); return 0;
}

Страшное случится, когда мы это запустим. Вместо ожидаемого порядка извлечения "3, 2, 1" мы увидим на экране консоли:

1,2,3
0
Для продолжения нажмите любую клавишу . . .

Если заменить оператор, помеченный комментарием //!!! на

cout << a.pop() << ","; cout << a.pop() << ",";  cout << a.pop();

то всё будет нормально:

3,2,1
0
Для продолжения нажмите любую клавишу . . .

Такие вещи способны свести с ума, пока не осознаешь некоторых концепций:

Коротко:
Нельзя рассчитывать на то, аргументы функции вычисляются слева направо.
Вызов функции, изменяющей некие величины, не нужно ставить в одном операторе с изменяемыми величинами!

4. Класс "Строка" с условием задачи:

Так как здесь мы именно моделируем строку, готовый класс string не уместен, но используется классический char *. Кроме текста строки, конечно, введём и свойство "размер". "Очищать" строку будем, просто зануляя первый байт. Как и в предыдущим примерах, для краткости не пишем явный деструктор и конструктор копирования.

Переопределённый оператор == не будет использовать свой правый аргумент, ну и что? Переопределённый постфиксный аргумент тоже не использует, но работает же :)

#include <iostream>
#include <cstring>
using namespace std;
class c {
 int size; char *text; //длина и сам текст
public:
 void show() { cout << endl << text; } //показать
 void clear() { size=0; text[0]='\0'; } //очистить
 c(int size=0) { //конструктор по умолчанию
  this->size = size;
  if (size>0) text = new char [size+1];
  else text=NULL;
 }
 c(char *text) { //конструктор с заданным знач.
  int size=strlen(text);
  if (size) {
   this->text = new char [size+1];
   strcpy(this->text,text);
  }
  else this->text = NULL;
 }
 c operator + (c &b) { //сцепление любого кол-ва строк
  int len = strlen(this->text) + strlen(b.text);
  c *d = new c(len);
  strcpy(d->text,this->text);
  strcat(d->text,b.text);
  return *d;
 }
 int operator == (int b) { return strlen(text); };
};

int main(void) {
 c a("Stroka"),b("Esche"),d("i esche");
 c e = a+b+d; e.show();
 int f=(e==0); cout << endl << f;
 cout << endl; system("pause"); return 0;
}

Я проверял это всё в QT, но и в Studio не должно быть разницы, кроме его склонности ругаться на "устаревшие" функции вроде strlen. На самом деле, устарели не функции, а Microsoft, вынужденный латать стандарты в поисках совместимости с эпохой однобайтовых кодировок и восьмибитных игрушек :)


теги: c++ программирование учебное

10.04.2017, 22:39; рейтинг: 1437

  свежие записипоиск по блогукомментариистатистика

Наверх Яндекс.Метрика
© PerS
вход