Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Infa (1)

.pdf
Скачиваний:
5
Добавлен:
14.04.2015
Размер:
2.31 Mб
Скачать

Circle();

Вы узнаете о роли конструктора позже в этом разделе, а пока запомните синтаксис, который используется в C++ для прототипа функции конструктора. Когда вы записываете прототип конструктора, вы должны следовать правилам, приведенным ниже:

Каждое объявление класса должно включать прототип функции конструктора.

Имя функции конструктора должно совпадать с именем класса, а после него должны следовать круглые скобки (). Если, например, вы объявляете класс с именем Rectangle, он должен включать объявление функции конструктора класса: Rectangle (). Следовательно, объявление класса Rectangle должно выглядеть так:

class Rectangle

{

public:

Rectangle(); // Конструктор

...

...

private:

...

...

};

Не упоминайте никакого возвращаемого значения для функции конструктора. (Функция конструктора должна иметь тип void, но не нужно это указывать.)

Функция конструктора должна располагаться под ключевым словом

public.

Функция конструктора всегда возвращает значение типа void (несмотря на то, что вы не указали его в прототипе). Как вы вскоре увидите, функция конструктора обычно имеет один или большее число параметров.

Функция деструктора

Функция деструктора записывается в объявлении класса следующим образом:

class Circle

(

public:

...

...

~Circle (); //Деструктор

private:

...

...

};

Обратите внимание на символ тильды (~), который предшествует прототипу функции деструктора. (На большинстве клавиатур вы можете найти символ тильды слева от клавиши 1.) При записи прототипа функции деструктора соблюдайте следующие правила:

Имя функции деструктора должно совпадать с именем класса и ему должен предшествовать символ ~. Если, например, вы объявляете класс с именем Rectangle, именем функции деструктора должно быть ~Rectangle. Следовательно, объявление класса Rectangle должно выглядеть следующим образом:

class Rectangle

{

public:

Rectangle(); // Конструктор

...

~Rectangle(); // Деструктор private:

...

...

};

Не указывайте никакого возвращаемого значения для функции деструктора. (Функция деструктора должна иметь тип void, но не нужно это указывать.)

Функция деструктора не имеет никаких параметров.

Ключевые слова public и private

Прототипы функций и объявления элементов данных включаются в объявлении класса в разделы public (открытый) или private (закрытый). Ключевые слова public и private говорят компилятору о доступности элементов-функций и данных. Например, функция SetRadius() определена в разделе public, и это означает, что любая функция программы может вызвать функцию SetRadius().

Функция CalculateArea() определена в разделе private, и эту функцию можно вызвать только в коде функций-элементов класса Circle

Аналогично, поскольку элемент данных radius объявлен в разделе private, прямой доступ к нему (для установки или чтения его значения) возможен только в коде функций-элементов класса Circle. Если бы вы объявили элемент данных radius в разделе public, то любая функция программы имела бы доступ (для чтения и присваивания) к элементу данных radius.

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

конструктор - функция, которая инициализирует переменную класса

деструктор – разрушает

конструктор вызывается при создании переменной или инициализации указателя функцией new может быть перегружен и иметь параметры по умолчанию не может быть вызван как функция без всего

деструктор имеет вид ~myClass();

не может быть перегружен и иметь значения по умолчанию так же не может иметь переменные может быть вызван как функция

при создании переменной вызывается конструктор класса myClass a(b,c);

или

myClass *a = new myClass(b,c); a - переменная типа myClass

в скобочках - параметры для ее инициализации, которые передаются в конструктор myClass::myClass (int a, int b)

{

}

этоконструктор int k = 1, l =2;

myClass peremennayaClassa(k,l); myClass{

myClass(int a,int b)

}

прототип конструктора, сам конструктор описывается вне класса как выше показано с двоетточием можетбытьтакое:

myClass{ const int x,y;

myClass::myClass (int a,int b):x(a),y(b) {}

}

инициализация параметров до функции это почти как:

myClass::myClass (int a,int b):

{

x=a;

y=b;

}

только в предыдущем случае будет работать даже с константами, т.е. если const int x,y;

Обычно при создании объекта класса необходимо провести начальную инициализацию объекта, например– выделить участок памяти для размещения каких-либо данных, связанных с этим объектом. После окончания использования объекта выделенную память надо освободить и отдать обратно операционной системе.

Язык С++ предоставляет удобное средство для инициализации и удаления объектов класса. Для этого предусмотрены специальные методы. Они называются конструкторами и деструкторами.

Функция конструктор имеет такое же имя как имя класса и позволяет выполнить инициализацию объекта класса в момент его создания. Конструктор может иметь параметры. Их надо будет указать при определении объекта данного класса. Класс может иметь несколько конструкторов с разными параметрами, то есть конструкторы могут быть перегружены.

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

Среди всех методов любого класса выделяются два, определяющие способы, какими создаются, инициализируются, копируются и разрушаются объекты класса. Речь идет о конструкторах (constructor) и деструкторах (destructor), которые наряду с характеристиками обычных методов обладают и некоторыми уникальными свойствами:

Конструктор всегда имеет то же имя, что и сам класс; это же относится и к деструктору, которому, однако, предшествует символ "~" (тильда).

Не имеют объявлений значений возврата (даже void).

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

Конструкторы, как и большинство функций C++, могут иметь аргументы по умолчанию или использовать списки инициализации элементов.

Деструкторы могут иметь атрибут virtual, а конструкторы — нет.

Нельзя работать с адресами конструкторов и деструкторов.

Если конструкторы или деструкторы не были определены явно, они генерируются компилятором.

Конструктор нельзя вызывать как обычную функцию; вызов деструктора возможем с полностью заданным именем.

При определении и разрушении объектов вызов конструкторов и деструкторов осуществляется автоматически.

Конструкторы и деструкторы при необходимости выделения объекту памяти могут выполнять неявные вызовы операций new и delete.

Прежде чем переходить к более подробному знакомству с этими специальными

методами классов, рассмотрим правила, по которым происходит создание/уничтожение объектов:

Конструкторы и деструкторы автоматически запускаются всякий раз при создании и разрушении объектов.

Глобальные и локальные статические объекты создаются в начале выполнения программы — до того, как управление попадает в main (или WinMain).

Уничтожение таких объектов происходит в момент завершения программы в результате возврата из функции main (WinMain).

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

Конструктор объекта, память которому выделяется в области Heap (Куча)

(посредством операцииnew), вызывается автоматически при вызове new; такой объект разрушается при явной передаче объекта в оператор delete.

Примечание

Для объектов, память под которые выделяется вызовом malloc (или аналогичной функции), конструктор не вызывается вообще, поскольку в этом случае функция просто не знает, какой конструктор надо запустить (эта функция не принимает никакой информации о типе).

Рассмотрим простой пример, для которого воспользуемся классической функцией main, чтобы избежать дополнительных действий, необходимых для Windows-приложений:

//Простой пример,

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

#include <stdio.h> #include <string.h>

//Объявляемкласс

classSample{

private: //К этим данным доступ возможен только посредством методов класса

char *strName;

public: // К этим данным доступ возможен из любого места программы // Определяемпростойконструктор

Sample(char *str){

strName = new char[strlen(str) + 1]; strcpy(strName, str);

printf("Entry in constructor for %s\n", strName);

}

// Определяемдеструктор, -Sample ()

{

printf("Entry in destructor for %s\n", strName); delete strName;

strName = 0;

}

}; // Определяемпервый.глобальныйобъект

Sample globall ("global #!");

//"Глупая" функция, иллюстрирующая Создание автоматического объекта void SillyFunc(){

//Определяем объект, локальный для данной функции

Sample fnAuto("automatic function"); printf ("Function SillyFuncO \n") ;

}

int main(int argc, char* argv[])

{

//Определяемпервыйлокальныйобъект

Sample autol("automatic #1") ; printf("Begin main()\n"); SillyFunc();

//Определяемвторойлокальныйобъект

Sample auto2("automatic #2"); printf("Continue main()\n"); return 0;

}

//Определяем второй глобальный объект

Sample globa!2("global #2");

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

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

Примечание

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

Некоторые конструкторы играют особую роль.

Рис. П1.3. Результат выполнения программы Sample

Конструктор по умолчанию

Конструктор по умолчанию не имеет аргументов и используется, когда объект создается без инициализации его данных:

class MyClass{ public;

MyClass() {}

// Остальные данные и методы

};

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

MyClass clObj;

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

class MyClass{ public: MyClass();

MyClass(intnArg =0);

// Остальные данные и методы

};

может возникнуть неопределенность при вызове конструктора

MyClass c!0bjl(7); //можно — однозначно вызывается

//MyClass::MyClass(int)

MyClass clObj2; // нельзя; неоднозначно задано, какой конструктор

// следует вызывать — MyClass: :MyClass (int.)

// или MyClass::MyClass(int nArg = 0)

Конструктор копирования

Аргументом конструктора может быть и сам объект класса. Конструктор в этом случае будет иметь следующий прототип:

MyClass::MyClass(MyClass &);

Такие конструкторы запускаются при копировании данных "старого" объекта во вновь создаваемый:

MyClass clObjl(7); MyClass clObjl = cl0bj2;

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

Несколько слов о деструкторах

В отличие от конструкторов, деструктор класса не имеет аргументов и не может быть перегружен. Как было наглядно продемонстрировано в примере на рис. П1.3, деструкторы вызываются строго в обратной последовательности вызова соответствующих конструкторов. Они вызываются автоматически при выходе объекта из блока, в котором были определены. Единственным исключением из этого общего правила является случай, когда объект создается динамически из "кучи", путем вызова оператора new. В этом случае для корректного удаления объекта необходимо явно выполнить оператор delete, который и вызовет необходимый деструктор.

Таким образом, можно подвести предварительные итоги. Понятие класса C++ устанавливает четко определенный интерфейс, который помогает разрабатывать, выполнять; поддерживать и сопровождать программы. Концепция класса органично связана с идеей абстракции данных, при которой данные не связываются ни с каким физическим воплощением, а скорее определяется в терминах методов (функций), выполняемых над ними. С этой точки зрения данные и методы рассматриваются как равные, независимые партнеры.

7) Разграничение доступа к элементам класса.

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

Для управления доступом к элементам класса предусмотрены ключевые слова public, private и protect (спецификаторы доступа). Методы и данные, определенные или описанные после ключевого слова public представляют собой интерфейс класса – они доступны для использования вне определения класса. Остальные члены класса относятся к его внутренней реализации и обычно недоступны вне класса. Различия между членами класса, описанными после ключевых слов private и protect сказываются только при наследовании от данного класса новых классов. Процедуру наследования мы рассмотрим позже.

Ключевые слова public, private и protect указываются в определении класса перед элементами класса, доступом к которым они управляют. Ключевые слова, управляющие доступом, могут быть указаны несколько раз в одном классе, порядок их расположения значения не имеет. По умолчанию элементы класса являются private. Рекомендуется всегда явно определять права доступа к членам класса.

public

Компонент доступен для любой функции protected

Компонент может быть использован методами или "друзьями" класса, в котором он объявлен, а также производных от него, но только в объектах производного класса

private

Компонент может быть использован только методами или "друзьями" класса, в котором он объявлен

Определены следующие значения доступа по умолчанию для компонентов классов, структур и объединений:

Класс, определенный с помощью ключевого слова struct — это класс, в котором все элементы по умолчанию являются общедоступными (public), и имеется возможность изменять этот уровень доступа.

Класс, определенный с помощью ключевого слова union — это класс, в котором все элементы по умолчанию являются общедоступными (public), и этот уровень доступа не может быть изменен.

Класс, определенный с помощью ключевого слова class — это класс, в котором все элементы по умолчанию являются частными (private), и имеется возможность изменять уровень доступа.

Друзья классов

В языке C++ предусмотрена возможность обеспечить доступ к частным и защищенным компонентам извне класса при помощи ключевого слова friend, которое говорит о том, что следующая за ним функция является "другом" данного класса и имеет полный доступ ко всем его компонентам, не являясь в то же время методом этого класса. Такие дружественные функции не зависят от положения в классе и спецификаторов доступа и ничем другим от обычных методов не отличаются.

class MyClass

{

private: int nVar;

// Дружественнаяфункция

friend void friendFunc. (MyClass SclArg, int nArg); public:

// Методкласса

void memberFunc(int nArg); } ; // Определенияфункций

void friend friendFunc(MyClass SclArg, int nArg) (clArg.nVar = nArg;}

void memberFunc(int nArg) {nVar = nArg;}

//Создаем объект класса

MyClass clObj;

//Обращаемся к частному компоненту класса

friendFunc(clObj, 7); memberFunc(7);

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

В качестве дружественной функции может выступать и некоторый метод другого класса:

class MyClassl

{

..

//Метод memberFuncMyClass2 класса MyClass2 объявляется дружественным

//классу MyClassl

friend void MyClass2::memberFuncMyClass2(...);

...

};

По аналогии с функциями и методами можно объявить дружественным весь класс. При этом все методы такого дружественного класса смогут обращаться ко всем компонентам класса:

class MyClass

{

...

// Класс MyFriend объявляется дружественным классу MyClass friend class MyFriend;

...

};

И еще два замечания:

1. "Дружба" классов не транзитивна. Другими словами, если класс MyClass 1 друг класса MyClass2, aMyClass2 друг MyClass3, то это не означает, что MyClassl друг MyClass3. Однако "дружба" наследуется, но об этом более подробно после знакомства с наследованием.

2. "Дружба" классов односторонняя, т. е. если класс MyFriend объявлен другом MyClass, то это не означает, что MyClass имеет доступ к частным и

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

8) Наследование.

Впринципе производный класс наследовал каждый элемент базового класса кроме:

его строитель и его деструктор

его действующая компания = () элементы

его друзья

Главная особенность классов C++ - наследственность. Наследственность позволяет создавать классы, которые выводятся из других классов, так, чтобы они автоматически включали некоторые из элементов ее "родителя", плюс ее собственное.

class Bird //птичка

{

int x,y;

int fly(int dx,int dy);

}

class Eagle: Public Bird //орел, наследуемыйотптицы

{

int eat(int x,int y);

}

класс орел будет иметь в себе переменные класса Bird и методы класса Bird

(кроме конструкторов и деструкторов)

И

свой метод eat

(съесть)

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

множественное наследование

class Person{

int x,y; //координаты

void printPosition(); //напечатать позицию

}

class Student: public Person{ int passTurns(); // сдатьсессию

}

class Prepod: public Person{

int getExam(); //принятьэкзамен

}

class Aspirant: virtual public Person, virtual public Student{ void go_and_work();

}

аспирант – наследник сразу двух классов

virtual используется чисто потому, что Person и Student наследуются от одного класса

иначе не скомпилится

из-за того, что переменные x,y будут дважды в новом классе

метод virtual помогает этого избежать

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]