Объединения и классы
• Union и class имеют много общего. Union может иметь конструктор, деструктор и дружественные функции. Все члены union по умолчанию public. Ключевые слова private, protected, public не могут использоваться в union. Union не могут использоваться в наследовании ни как базовый, ни как производный типы. • В С++ можно использовать неименованные (anonimus) union: • union {список-элементов}; • Неименованные union определяют объект, а не тип. Имена элементов union используются без операции точка, и имена должны отличаться от других имен из области действия.
Пример: • • • #include <iostream. h> void main() { union { long l; unsigned char ch[4]; }; cout<<”n Give number type long: ”; cin>>l; cout<<” 1 byte: ”<<int(ch[0])<<endl; cout<<” 2 byte: ”<<int(ch[1])<<endl; cout<<” 3 byte: ”<<int(ch[2])<<endl; cout<<” 4 byte: ”<<int(ch[3])<<endl; }
Наследование классов
Терминология: • Класс, который наследуется – базовый класс (base class); • Класс, который является наследником – производный класс (derived class) (или child class); • Режимы доступа: public, private, protected.
Пример • • • class X { // Базовый класс int i, j; public: void get_ij(void); void put_ij(void); }; class Y: public X { // Производный класс int k; public: int get_k(void); void make_k(void); };
Для обеспечения доступа членовфункций класса Y к элементам i и j класса X нужно в классе X объявить их protected • class X { // Базовый класс • protected: • int i, j; • public: • …
Основная форма наследования • • • class имя-производного-класса: режимдоступа имя-базового-класса {…}; режим доступа {private, protected, public} Если режим доступа отсутствует, то по умолчанию: public – если производный класс структура; private – если производный класс class.
Схема режимов доступа при наследовании Режим доступа к элементу в базовом Режим доступа при наследовании классе Режим доступа к производном классе private недоступен protected ---- public protected public private недоступен protected ---- protected public protected private недоступен protected ---- private public private элементу в
// Наследование режима доступа • • #include <iostream. h> class X{ protected: int i, j; public: int get_ij(void); void put_ij(void); };
• • • • class Y: public X{ int k; public: int get_k(void); void make_k(void); }; // i, j стали protected членами в классе Y class Z: public Y{ public: void f(void); }; // Z имеет доступ к переменным класса Х // Z не имеет доступа к переменной k класса Y
• • • • • • void X: : get_ij(void) { cout<<”Введите два числа: ”; cin>>i>>j; } void X: : put_ij(void) { cout<<”i=”<<i<<” j=”<<j<<endl; } int Y: : get_k(void) { return k; } void Y: : make_k(void) { k=i*j; } void Z: : f(void) { i=2; j=3; }
• • • • void main(void) { Y v 1; Z v 2; v 1. get_ij(); v 1. put_ij(); v 1. make_k(); cout<<v 1. get_k()<<endl; v 2. f(); v 2. put_ij(); v 2. make_k(); cout<<v 1. get_k(); cout<<end; }
// простое наследование • • • • #include <stdio. h> #include <conio. h> #include <iostream. h> #include <string. h> const int MAX_LEN =10; class Coord { protected: int x, y; public: Coord(int _x=0, int _y=0); void Set. Loc(int _x, int _y); };
• • • • • Coord: : Coord(int _x, int _y) { Set. Loc(_x, _y); } void Coord: : Set. Loc(int _x, int _y) { x = _x; y = _y; } //Msg. At. Coord: Содержит сообщение, наследует от Coord class Msg. At. Coord : public Coord { char msg[MAX_LEN]; public: Msg. At. Coord(char *_msg = “NO MSG” ); void Set. Msg(char *_msg); void Show(); };
• • • • Msg. At. Coord: : Msg. At. Coord( char *_msg) { Set. Msg( _msg); } void Msg. At. Coord: : Set. Msg(char *_msg) { strcpu( msg, _msg); } void Msg. At. Coord: : Show() { gotoxy(x, y); printf( msg); }
• void main(void) • { • Msg. At. Coord greeting; • greeting. Set. Loc( 10, 10); • greeting. Set. Msg(“ hello…”); • greeting. Show(); • }
Конструкторы с параметрами при наследовании
• #include <iostream. h> • // простое наследование, конструкторы с параметрами • class X { • protected: • int x; • public: • X(int i); // Конструктор с параметром • ~X(void); // Деструктор • void put_x(int i) { x = i; } • int get_x(void) { return x; } • void show(void); • };
• • • class Y: public X { protected: int y; public: Y(int i, int j); // Конструктор с параметром ~Y(void); // Деструктор void put_y(int i) { y = i; } int get_y(void) { return y; } void show(void); };
• • • class Z: public Y{ protected: int z; public: Z(int i, int j); // Конструктор с параметром ~Z(void); // Деструктор void make_z(void); void show(void); };
• • • • X: : X(int i) { x=i; cout<<”n Конструктор Хn”; } X: : ~X(void) { cout<<”n деструктор Xn’; } void X: : show(void) { cout<<”n x=”<<x<<endl; }
• Y: : Y(int i, int j): X(i) • // конструктор класса У передает значение конструктору класса Х, поэтому • // он должен иметь два параметра • { • y=j; • cout<<”n Конструктор Yn”; • } • Y: : ~Y(void) • { • cout<<”n деструктор Yn’; • } • void Y: : show(void) • { • cout<<”n x=”<<x<<” y=”<<y<<endl; • }
• Z: : Z(int i, int j): Y(i, j) • // конструктор Z передает значения параметров конструктору Х, поэтому • // он должен иметь два параметра • { • cout<<”n Конструктор Zn”; • } • Z: : ~Z(void) • { • cout<<”n деструктор Zn’; • } • void Z: : make_z(void) • { • z=x*y; • } • void Z: : show(void) • { • cout<<z<<” = ”<<x<<” *”<<y<<endl; • }
• void main(void) • { • Z zobject(3, 5); // создание и инициализация объекта • zobject. make_x(); • zobject. show(); • zobject. X: : show(); // вызов функции • zobject. Y: : show(); // show из разных классов • zobject. put_x(7); // новые значения • zobject. put_y(9); // переменных x, y • zobject. make_z(); • zobject. show(); • zobject. X: : show(); // вызов функции • zobject. Y: : show(); // show из разных классов • }
• В этом примере использовалась следующая схема наследования • class X ------ • class Y ---- class Z •
• Множественное наследование Язык С++ позволяет наследование не только от одного, а одновременно от нескольких классов. Форма наследования следующая: class имя-производного-класса: список базовых классов { // ……. . };
• Список базовых классов содержит перечисленные базовые классы с соответствующими режимами доступа к каждому из базовых классов. Пример • class Z: public U, public V, protected W {// …. };
Пример • • • #include <iostream. h> class X { protected: int x; public: X(int i); // Конструктор с параметром ~X(void); // Деструктор void put_x(int i) { x = i; } int get_x(void) { return x; } void show(void); };
• • • class Y { protected: int y; public: Y(int i); // Конструктор с параметром ~Y(void); // Деструктор void put_y(int i) { y = i; } int get_y(void) { return y; } void show(void); };
• • • class Z: public X, public Y{ protected: int z; public: Z(int i, int j); // Конструктор с параметром ~Z(void); // Деструктор void make_z(void); void show(void); };
• • • • X: : X(int i) { x=i; cout<<”n Конструктор Хn”; } X: : ~X(void) { cout<<”n деструктор Xn’; } void X: : show(void) { cout<<”n x=”<<x<<endl; }
• • • • Y: : Y(int i) { y=j; cout<<”n Конструктор Yn”; } Y: : ~Y(void) { cout<<”n деструктор Yn’; } void Y: : show(void) { cout<<”n y=”<<y<<endl; }
• Z: : Z(int i, int j): X(i), Y(j) • // конструктор Z передает значения параметров конструкторам Х и Y, поэтому • // он должен иметь два параметра • { • cout<<”n Конструктор Zn”; • } • Z: : ~Z(void) • { • cout<<”n деструктор Zn’; • } • void Z: : make_z(void) • { • z=x*y; • } • void Z: : show(void) • { • cout<<z<<” = ”<<x<<” *”<<y<<endl; • }
• void main(void) • { • Z zobject(3, 5); // создание и инициализация объекта • zobject. make_x(); • zobject. show(); • zobject. X: : show(); // вызов функции • zobject. Y: : show(); // show из разных классов • zobject. put_x(7); // новые значения • zobject. put_y(9); // переменных x, y • zobject. make_z(); • zobject. show(); • zobject. X: : show(); // вызов функции • zobject. Y: : show(); // show из разных классов • }
Замечание • • • основная форма: конструктор-производного-класса(список аргументов): базовый-класс1(список аргументов), базовый-класс2(список аргументов), … базовый-класс. N(список аргументов) { … } Базовый-класс. I – имя конструктора базового класса, который наследуется производным классом
Перегрузка функций и операций
Пример • • • #include <iostream. h> #include <stdio. h> #include <time. h> class timer { int seconds; public: timer(void) {seconds=5; } // конструктор по умолчанию timer(char *t) { seconds=atoi(t); } // время задается строкой timer(int t) {seconds=t; } // Задание секунд целым числом timer (int min, int sec) { seconds=60*min+sec; } // задание минутами и секундами void run(void); };
• • • • void timer: : run(void) { clock_t t 1, t 2; t 1=t 2=clock()/CLK_TCK; while(seconds) { if (t 1/CLK_TCK+1<=(t 2=clock())/CLK_tck) { seconds--; t 1=t 2; } } сout<<”a”; // сигнал }
• void main(void) • { • timer a(10), b(“ 20”), c(1, 10), d; • сout<<”Подождите 10 секунд…n”; • a. run(); // 10 секунд • сout<<”Подождите 20 секунд…n”; • b. run(); // 20 секунд • сout<<”Подождите 1 минуту 10 секунд…n”; • с. run(); // 1 минута 10 секунд • сout<<”Подождите 5 секунд…n”; • d. run(); // 5 секунд • }
• Язык С++ позволяет определять и применять к вашему классу обозначения операций. • Эта особенность, называемая перегрузкой операций, дает классу возможность вести себя подобно встроенному типу данных. Можно перегружать для классов любые из следующих операций
Можно перегружать для классов любые из следующих операций + - * . % ^ & | ! = < > += -= /= %= ^= ^= &= |= << >>= <<= = = != != <= >= && || ++ -- []
• Чтобы перегрузить операцию, нужно определить, что эта значит относительно класса, к которому она будет применяться. Для этого создается специальная функцияоперация (operator function), которая определяет действие этой операции
Основная форма функции-операции, являющейся функцией-членом класса Тип имя-класса: : operator #(список аргументов) { // операторы, определяющие действие } тип – тип возвращаемого значения; # - конкретный знак операции.
Пример • Перегрузка операций + и = относительно класса vector, который определяет трехмерный вектор в эвклидовом пространстве. Операция сложения векторов выполняется как сложение соответствующих координат
• • • #include <iostream. h> class vector { int x, y, z; // координаты public: vector operator +(vector t); vector operator =(vector t); void show(void); void assign(int mx, int my, int mz); };
• • • // перегрузка операции + vector: : operator + (vector t) { vector temp; temp. x=x+t. x; temp. y=y+t. y; temp. z=z+t. z; return temp; }
• • • // перегрузка операции = vector: : operator = (vector t) { vector temp; x=t. x; y=t. y; z=t. z; return *this; }
Функции ввода-вывода • • void vector: : show(void) { cout<<x<<” “<<y<<” “<<z<<endl; } void vector: : assign(int mx, int my, int mz) { x=mx; y=my; z=mz; }
• void main(void) • { • vector a, b, c; • a. assign(1, 2, 3); • b. assign(4, 5, 6); • a. show(); • b. show(); • c=a+b; // использование перегруженной операции + • c. show(); • c= a + b + c; • c. show(); • c = b = a; • c. show(); • b. show(); }
Пример Перезагрузки унарных операции ++ и --
• class vector { • int x, y, z; // координаты • public: • vector operator +(vector t); • vector operator =(vector t); • vector operator++(void); // префиксная операция • vector operator++(int); // постфиксная операция • void show(void); • void assign(int mx, int my, int mz); • };
• • • vector: : operator ++(void) { // префиксная x++; y++; z++; return *this; }
• • • vector: : operator ++(int) { // постфиксная vector tmp; tmp=*this; x++; y++; z++; return tmp;
• void main(void) • { • vector a, b, c; • a. assign(1, 2, 3); • b. assign(4, 5, 6); • a. show(); • b. show(); • c=a+b; // использование перегруженной операции + • c. show(); • c= a + b + c; • c. show(); • c = b = a; • c. show(); • b. show(); • с++; // использование постфиксной операции • c. show(); • ++с; // использование префиксной операции • c. show(); • }