Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курсовые / Язык программирования Сpp 25.09.11.doc
Скачиваний:
114
Добавлен:
10.05.2015
Размер:
10.13 Mб
Скачать

Демонстрационные программы

Рассмотрим интересный класс с названием стек. С его помощью можно создать реальный стек. Напомним, что стек это устройство, работающее по принципу последним вошел – первым вышел. Примером такого устройства может являться детская игрушка – пирамида, представляющая собой стержень (stack) на который надеваются кольца разного диаметра. В этой игре первым со стека снимается кольцо, которое было надето последним. В нашей задаче, конечно, будет использоваться стек для чисел.

#include <iostream>

using namespace std;

#include <windows.h>

#define SIZE 100 //размер стека

//Определение класса stack

class stack{

int stck[SIZE]; /*массив,в котором хранятся числа,

записанные в стек, это не сам стек */

int tos; //переменная показывающая заполнение стека

public:

void init(); //функция инициализации стека

void push(int i); //функция записи (протягивания) в стек

int pop(); //функция уменьшения указателя очереди

};

//------конец класса, далее идет описание функций -------------

void stack::init(){ //установка указателя номера на ноль

tos=0;

}

//----------------------------

void stack::push(int i){

if(tos==SIZE){

cout<<”Стек полон”<<endl;

return;} // return говорит об окончании выполнения кода функции

stck[tos]=i;

tos++;

}

//-----------------------------

int stack::pop(){

if(tos==0){

cout<<”Стек пуст”<<endl;

return 0;

}

tos--;

return stck[tos];

}

//-------------------------

int main(){

stack stack1, stack2; //Создаем объекты класса stack

stack1.init(); //Опустошаем стеки

stack2.init();

stack1.push(1);

stack2.push(2);

stack1.push(3);

stack2.push(4);

cout<<stack1.pop()<<” “;

cout<<stack1.pop()<<” “;

cout<<stack2.pop()<<” “;

cout<<stack2.pop()<<” “;

return 0;

}

Результат работы программы

3 1 4 2

т.е. числа из обоих стеков выходят в обратном порядке.

Попробуйте на базе данного примера создать программу в которой имеется два стека. Числа в стеки записываются с клавиатуры. Количество записаных чисел в каждый стек может быть разным.

7.2. Конструкторы и деструкторы

Теперь, когда мы имеем некоторое представление о классах и объектах, давайте задумаемся над тем, как задать начальные значения переменным класса. Например, имеется класс

class MyClass{

public:

int a,b,c;

void print();

};

void MyClass::print(){

cout<<”a=”<<a<<endl<<”b=”<<b<<endl<<”c=”<<c;

}

Нужно инициализировать переменные a,b,c.

Напомним, что класс состоит из объявлений и прототипов функций. Задать начальные значения переменных, т.е. написать, например,

int a=0,b=1,c=2;

нельзя, т.к. класс это некий шаблон кода в котором нельзя инициализировать переменные. Если попытаться запустить функцию print(), то на экране появятся случайные числа, оказавшиеся в выбранных компилятором ячейках памяти. Они остались там от предыдущей прграммы.

Если учесть что класс это тип данных то вопрос можно сформулировать так: как присвоить такому типу данных начальные значения? Можно конечно поступить так: создать объект, а потом вызвать его параметры через оператор точка. В данном случае это выглядит так:

MyClass mc;

mc.a=0; mc.b=1; mc.c=2;

Согласитесь, что это не очень удобно. Оказывается в С++ для этого предусмотрены специальные средства. Это так называемые конструкторы.

Конструктор это функция специального вида, которая используется для инициализации нескольких или всех переменных-членов, и для других инициализирующих действий. Скажем сразу, что программист может не создавать конструктор, но тогда сам компилятор автоматически создаст конструктор, который, правда, не выполняет никаких действий.

Отличие конструктора от функций состоит в следующем:

  1. Имя конструктора должно совпадать с именем класса. Например, класс MyClass должен иметь конструкторMyClass().Правда, в рассмотренном примере его нет, в силу того, что он был создан автоматически или, как говорят, по умолчанию.

  2. Конструктор не возвращает никакого значения.

  3. В начале прототипа или в заголовке не должно присутствовать указание на какой либо тип, даже на void.

  4. Конструктор должен находиься в секции public.

Рассмотрим простой пример программы выполняющей ввод и сложение двух чисел.

Таким образом рассмотренный приер класса должен выглядеть так:

#include <iostream.h>

class MyClass{

public:

int a,b,c;

MyClass();

void print();

};

void MyClass::print(){

cout<<”a=”<<a<<endl<<”b=”<<b<<endl<<”c=”<<c;

}

MyClass::MyClass(){

a=0,b=1,c=2;

}

Обратите внимание, что в описании класса также присутствует только прототип конструктора. Его описание производится также как и обычной функции, с той лишь разницей, что не указывается тип возвращаемой величины.

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

#include <iostream.h>

class MyClass{

public:

int a,b,c;

MyClass(int x,int y,int z);

void print();

};

void MyClass::print(){

cout<<"a="<<a<<endl<<"b="<<b<<endl<<"c="<<c;

}

MyClass::MyClass(int x,int y,int z){

a=x, b=y, c=z;

}

Работа программы с созданным классом может быть выглядеть так:

int main(){

MyClass mc(0,1,2);//создание объекта с инициализацией

mc.print();

char z;

cin>>z;

return 0;

}

Рассмотрим более сложный пример. Создадим класс для суммирования двух чисел, вводимых с клавиатуры.

//Программа суммирования двух чисел

#include <iostream>

using namespace std;

class Summa {

public:

double z;

Summa(double x,double y);

};

//описание конструктора

Summa::Summa (double x, double y){

z=x+y;

}

//------------

void main(){

double x,y;

cin>>x>>y;

Summa sum(x,y); /*объявление объекта класса Summa или

неявный вызов конструктора */

cout<<"\nRESULT="<<sum.z; /*переменная класса вызывается через

имя класса и имя переменной, разделенных точкой */

}

В рассмотренном примере был использован, так называемый неявный вызов конструктора. Здесь при объявлении объекта с именем sumуказаны его данные необходимые для конструктора.

Вместо строки

Summa sum(x,y);

можно было использовать явный вызов

Summa sum; //объявление объекта

sum= Summa(x,y); //инициализация

но этот способ инициализации некоторыми компиляторами не поддерживается.

Объявление можно совместить с инициализацией, подобно тому как это делается с базовыми переменными:

Summa sum=Summa(x,y);//объявление и инициализация

При объявлении объектов конструктор вызывается автоматически. Однако конструктор можно вызвать еще раз, подобно тому как это можно делать с обычной функцией. Конструктор должен быть открытым членом класса. Иначе к нему не будет доступа извне.

Заметим, что конструкторов может быть несколько, впрочем, как и функций с одним именем. Иначе говоря, конструктор может быть перегруженным. Для лучшего понимания сказанного рассмотрим пример программы в которой используется класс с двумя конструкторами. Программа предназначена для суммирования чисел, которые могут быть как действительными, так и комплексными.

//Программа для суммирования чисел

#include <iostream>

using namespace std;

class Summa {

public:

Summa(double x,double y); /*Конструктор для суммирования

* действительных чисел x,y */

Summa(double x,double y,double u,double v); /*Конструктор

* суммирования комплексных чисел x+iy, u+iv */

double Re, Im;

}; //Конец класса

//Определение первого конструктора

Summa::Summa(double x,double y){ //Оператор :: называется

Re=x+y; //оператором разрешения области

Im=0; //видимости

}

//Определение второго конструктора

Summa::Summa(double x,double y,double u,double v){

Re=x+u;

Im=y+v;

}

//====================================================

void main(){

bool rule=true; /*Вспомогательная переменная которая определяет

* правило прерывания бесконечного цикла */

double x,y,u,v,z,w;

char ch;

while(rule){

//Выясняем тип чисел для сложения

cout<<"\n\n What numbers do yuor want take summa";

cout<<"Real or Complex\n";

cout<<"If Real inpur R or r if complex then C or c\n";

cin >>ch;

if ((ch=='R') || (ch=='r')){ /*выполняется если числа

* действительные */

cin>>x>>y;

Summa sumRe(x,y); //Создание объекта с именем sumRe

cout<<sumRe.Re;

}

if ((ch=='C') || (ch=='c')){ //выполняется если числа комплексные

cin>>x>>y>>u>>v;

Summa sumCompl(x,y,u,v);

cout<<sumCompl.Re<<" + i"<<sumCompl.Im;

}

if((ch='R')||(ch='r')||(ch='C')||(ch='c')) rule=true;

else rule=false;

}

}

В данном примере конструкторы не просто инициализируют объекты, но и выполняют арифметические действия. Это говорит о том, что конструктор можно использовать для выполнения более сложных задач, чем просто инициализация. При необходимости, в конструкторе можно описать всю программу. Нужно сказать, что конструктор, впрочем, как и функция, может не содержать параметров или иметь параметры по умолчанию. Наконец, в отличие от обычных функций класса, которые в теле класса представлены только в виде прототипов, тело конструктора можно описывать внутри класса.

Рассмотрим пример класса, в котором используется многое из того, о чем было сказано.

class Numbers{

public:

Numbers(int a=1,int b=2, int c=3){//значение по умолчанию

// описание конструктора внутри класса

/* конструктор может использовать имена параметров совпадающие с

* именами полей класса*/

Numbers::a=a;

Numbers::b=b;

Numbers::c=c;

}

show(); //функция класса

private:

int a,b,c; //параметры класса

};

//--------------функия main()----------------

void main(){

Numbers one(1,1,1);

Numbers two(20,30,40);

Numbers defaults;

one.show();

two.show();

defaults.show();

char z;

cin>>z;

}

//-----------описание функции класса-----------

Numbers::show(){

cout<<a<<" "<<b<<" "<<c<<endl;

}

В данном примере объекты oneиtwoопределяются своими наборами чисел, а объектdefaultsинициализируется числами по умолчанию. Конструктор с параметрами по умолчанию гарантирует инициализацию объекта тогда, когда программист забудет это сделать.

В результате на экране появится:

Как правило, в процессе работы программы отпадает надобность в использовании части созданных ранее объектов. Такие объекты просто занимают память. И хотя память современных компьютеров достаточно большая, порой накопление ненужных объектов приводит к её переполнению. Поэтому программист должен следить за тем, чтобы ненужные в дальнейшем объекты своевременно удалялись. Для разрушения существующих объектов в С++ используется специальные функции-члены классов, которые называются деструкторы. Подобно конструктору, деструктор имеет имя класса, впереди которого ставится знак тильда ~. Тип возвращаемого значения не указывается. Синтаксис деструктора следующий:

~имя_класса(){ //тильда и имя без пробелов

//операторы тела деструктора

};

Деструктор это тоже функция, которая не имеет параметров, но может иметь тело. Правда, в теле можно записать совсем немного. Ведь деструктор, после завершения своей работы все равно все уничтожит. Например, можно вывести на экран сообщение о завершении работы класса.

Как всегда, рассмотрим пример:

#include<iostream.h>

#include<windows.h>

//-------------------------------

class Book{

public:

char title[256];

char author[64];

float price;

Book(char *title, char *author,char *publisher, float price);

~Book();

void show_title();

float get_price();

void show_book();

void assign_publisher(char *name);

private:

char publisher[256];

void show_publisher();

};

//--------------------------------

void main(){

SetConsoleOutputCP(1251);

Book primer("C/C++ Примеры и задачи","", "Новое знание",305.0);

primer.show_book();

primer.~Book();

Book classic("Война и мир","Толстой Л.Н.", "Художественная литература", 1000.0);

classic.show_book();

char z;

cin>>z;

}

//----------------------------------

Book::Book(char *title, char *author, char *publisher, float price){

strcpy(Book::title, title);

strcpy(Book::author, author);

strcpy(Book::publisher, publisher);

Book::price=price;

}

//----------------------------------

Book::~Book(){

cout<<"Экземпляр класса закончил работу\n";

}

//---------------------------------

void Book::show_title(){

cout<<author<<" "<<title<<" "<<price<<endl;}

float Book::get_price(){

return price;

}

//----------------------------------

void Book::show_book(){

show_title();

show_publisher();

}

//-----------------------------------

void Book::assign_publisher(char *name){

strcpy(publisher, name);

}

//-------------------------------------

void Book::show_publisher(){

cout<<publisher<<endl;

}

Область видимости класса

Область видимости классов C++, как в случае обычных типов и переменных, распространяется от места их определения до конца блока, в котором это определение дается. Для расширения об­ласти видимости класса его можно определить вне всех программных блоков. Кроме того, если класс определен как внешний (extern), то он доступен для всей программы в целом.

Если класс определен как static, то его область видимости такая же, как и для переменной класса памяти automatic, но ее содержимое при этом сохраняется на протяжении всей про­граммы.

В следующем примере в классе Y функция-член func():

- используя : :с-, ссылается на глобальную переменную с;

- используя X: :c, ссылается на переменную внешнего класса;

- используя c ссылается на переменную X: :Y: :c вложенного класса.

Все тpu переменные с именем с доступны при использовании оператора расширения области

видимости

char c; /*Внешняя область видимости*/

class X{/* Объявление класса X */

public:

char c; /* X::c */

class Y{/* Объявление вложенного класса Y */

public:

void func(char e){ X t; :: c=t.X::c=c=e;}

private:

char c; /* X::Y::c */

};

};