Борис Пахомов Санкт Петербург бхв петербург 2013 удк 004. 4 Ббк 32. 973. 26018. 2 П
Скачать 17.38 Mb.
|
Полиморфизм8. Классы в С. Объектно - ориентированное программирование В этом классе определен метод draw (рисовать фигуру. Классы, рисующие различные фигуры и произошедшие от Object — родственные классы. Каждый из них определяет рисование своей фигуры методом draw , унаследованным от Object : точку, линию, прямоугольник, окружность и т. д. Но все фигуры разные, хотя метод общий. Но этот метод draw в каждом из классов-потомков переопределен, те. в каждом классе-потомке ему назначена другая функциональность. Полиморфизм достигается за счет того, что методам из класса-родителя позволено выполняться в классе-потомке, а там оставляют только его имя, но при этом дают ему необходимую для данного класса функциональность. Такие методы должны объявляться в обоих классах с атрибутом virtual , записываемым перед атрибутом "возвращаемый тип данных. Если функция имеет атрибут virtual , то она может быть переопределена в классе-потомке, даже если количество и тип ее аргументов такие же, что и у функции базового класса. Переопределенная функция отменяет функцию базового класса. Кроме атрибута virtual , у методов существует атрибут friend . Методы с таким атрибутом, расположенным (как и атрибут virtual ) в объявлении метода перед указанием типа возвращаемых данных, называются дружественными. Метод, объявленный с атрибутом friend , имеет полный доступ к членам класса, расположенным в секциях private и protected , даже если этот метод — не член этого класса. Это справедливо и для классов внешний класс (те. его методы) имеет полный доступ к классу, который объявляет этот внешний класс дружественным. Во всех остальных аспектах дружественный метод — это обычный метод. Подобные методы из внешних классов, имея доступ к секциями, могут решать задачи, реализация которых с помощью методов-членов данного класса затруднительна или даже невозможна. Примеры создания классов Приведем пример двух программ, в которых объявлены и использованы простейшие классы. Пример Программа показана в листинге 8.2, результат работы программы — на рис. 8.2. Как работает программа, видно из строк комментария в телепрограммы. Листинг 8.2 //8.1_2011.cpp #include "stdafx.h" #include #include 8. Классы в С. Объектно - ориентированное программирование Рис 8.2. Результат работы программы листинга Среда исполнения приложений в С/С++ выделяет два вида памяти статическую и динамическую. Последняя носит название "куча. Куча может быть управляемой и неуправляемой. Если компилятор способен определить размер памяти под объявленную переменную, то он выделяет для нее место в статической памяти (например, под переменную типа int он выделит 4 байта, а под массив типа int из 10 элементов он выделит 40 байтов. Если же компилятор не в состоянии определить размер памяти под объявленную переменную, то он потребует от программиста поместить такую переменную в куче в динамической памяти. Кстати, если программист сам хочет работать с динамической памятью (даже когда компилятор может поместить переменную в статической памяти, то язык это ему позволяет. Для простых переменных при этом используются функция malloc() , которая выделяет область памяти в динамической области и возвращает указатель на эту область, и функция free() , которая освобождает занятую переменной область и передает освобожденную память в общее пользование. Если же работа происходит с объектами, то здесь используются операторы new — аналоги аналог free() . Указанные функции и аналогичные им операторы работают с неуправляемой кучей. С управляемой кучей работает утилита, и нет необходимости освобождать самому память от объекта, поскольку в этом случае работает так называемая автоматическая сборка мусора когда объект становится ненужным, память от него освобождается. Чтобы работать с такой кучей, надо перейти в режим CLR. Что касается вопроса "почему, то очевидно, что компилятор размещает переменную типа класса, объявленного нами, в статической области памяти. Но приведем пример этой же программы, в которой используется по нашему желанию) динамическая память (мы, естественно, приводим только тело функции main() , где это отражается. int main() { A *min =(A *) new A(); создание экземпляров классов A, B B *max= (B *) new B(); min->a=10; Работа с элементами класса А из секции public min->b=20; int x1=min->f1(min->a,min->b); int x2=max->f2(10); // Работа с элементом класса B printf("x1=%d\nx2= %d\n",x1,x2); _getch(); 8. Классы в С. Объектно - ориентированное программирование обработка класса в головной программе int main() { produce izd; определение объекта из класса (экземпляр класса) izd.setpart(100, 200, 250.5); вызов метода класса izd.show(); вывод данных _getch(); } Рис 8.3. Результат работы программы листинга Этот небольшой созданный нами класс позволяет выводить на экран характеристики изделия, описанного в нем. Пример Используем класс, созданный в примере 2, для создания нового класса — наследника класса из примера 2. Новый класс должен будет задавать дополнительную характеристику изделия — его форму. Пример программы приведен в листинге 8.4, результат работы программы — на рис. 8.4. Листинг 8.4 // 8.3_2011.cpp #include "stdafx.h" #include #include { private: int modelnumber; номер изделия int partnumber; номер детали float cost; стоимость детали public: установка данных //функция-член класса присваивает данным класса значения своих параметров 8. Классы в С. Объектно - ориентированное программирование Конструктор класса Конструктор класса тоже член класса, но специфический — это метод с таким же именем, что и класс. Такие методы не имеют право возвращать какие-либо значения если вы написали в конструкторе оператор return , компилятор выдаст ошибку. Конструктор выполняет различные задачи и невиден вам как программисту. Даже если вы сами не писали его текст, конструктор по умолчанию всегда присутствует в классе, ибо основная его задача — создавать в памяти экземпляр класса (те. как бы по проекту (классу) построить дом (экземпляр класса. В этом случае конструктор берется из общего прародителя классов — класса Object , в котором он имеется. Вторая задача конструктора — придавать всем членам-данным класса начальные значения — инициализировать класс. Если вы сами не построили конструктор, который станет инициализировать члены-данные вашего класса вашими же значениями, то этим данным невидимый для вас конструктор (конструктор по умолчанию) придаст свои, принятые в системе для данного типа величин значения (например, данные типа int получат нулевые значения и т. д. В листинге 8.5 приведен пример класса с конструктором, созданным для инициализации членов-данных класса теми значениями, которые задаст пользователь класса при работе с ним. Листинг 8.5 // 8.4_2011.cpp #include "stdafx.h" #include #include { public: Это члены-данные класса. Сними будут работать функции-члены класса get... и set...*/ int month; int day; int year; Date( int dy, int mn, int yr конструктор класса { /*члены-данные day, month, year будут принимать значения, которые поступят в конструктор как в функцию при его использовании где-нибудь в приложении day=dy; month=mn; year=yr; } 8. Классы в С. Объектно - ориентированное программирование { return Date::year; } //--------------------------------- void Date::setYear(int yr ) { Date::year = yr; } //======================================================== int main() Работа с созданным классом { здесь с помощью конструктора в экземпляре класса (экземпляр с именем MyDate) устанавливаются заданные пользователем значения Date MyDate(12,3,2012); здесь определяется и инициализируется экземпляр MyDate класса Date int d,m,y; d=MyDate.getDay(); //d=12 m=MyDate.getMonth(); //m=3 y=MyDate.getYear(); //y=2012 printf("d=%d, m=%d, y=%d\n",d,m,y); Date BirthDate ( 1, 12, 1938 ); изменить значение месяца назначение в экземпляре MyDate:*/ MyDate.setMonth( 4 ); m=MyDate.getMonth(); // m=4 изменить значение месяца назначение в экземпляре BirthDate: */ BirthDate.setMonth( 5 ); m=BirthDate.getMonth(); //m=5 _getch(); } Результат работы приложения показан на рис. 8.5. Рис 8.5. Работа конструктора класса Заметим, что у класса может быть много конструкторов. Когда создается класс, то для инициализации его различных полей и создаются различные конструкторы. Хотя все они имеют одинаковое имя, совпадающее с именем класса, тем не менее компилятор их различает по различным наборам параметров и типов. 8. Классы в С. Объектно - ориентированное программирование Это обычные классы, только атрибут ref указывает, что его класс надо размещать в управляемой куче. Например MyClass ^mc = gcnew Здесь gcnew для экземпляра класса выделяет память и размещает объект в куче и выдает указатель mc на начало объекта. Если же попробовать объект разместить в куче, то компилятор выдаст ошибку. А для класса с атрибутом value компилятор разрешает это делать, те. оператор MyClassV *vv=new MyClassV(); срабатывает. Пример int main() Головная функция { MyClass ^mc = gcnew идет // MyClass *mc=new не идет mc->m_i=111; присвоили значение члену класса int mci=mc->m_i; достали значение из класса //MyClassV ^vv=gcnew MyClassV(); идет MyClassV *vv=new MyClassV(); идет vv->m_i=222; int mv=vv->m_i; Console::WriteLine("mci=" + mci + " mv= " + mv); delete vv; сами должны удалять объект из кучи } Результат: mci=111 и mv= Оказывается, что можно ссылаться из типа на тип. Например, функция в типе (классе или структуре) может принимать параметр например, struct ). При этом если тип и функция имеют атрибут доступа public , то и тип должен иметь атрибут Например include "stdafx.h" using namespace тип public struct N { int i; }; public ref struct R тип // функция, у которой параметр nn имеет тип N, те. параметр – структура 158 Часть I. Изучение языка С/С++ int f(N nn) { nn.i++; return(nn.i); } }; int main() Головная функция { R ^r = gcnew R; N n; n.i=333; int ni=r->f(n); Console::WriteLine("ni=" + Абстрактные классы Методы класса могут быть объявлены как абстрактные. Это означает, что в этом классе нет реализации этих методов. Абстрактные методы пишутся с модификатором. Класс, в котором есть хотя бы один абстрактный метод, называется абстрактным (в таком классе могут быть и обычные методы. Нельзя создавать экземпляры абстрактного класса — такой класс может использоваться только в качестве базового класса для других классов. Для потомка такого класса есть две возможности или он реализует все абстрактные методы базового класса (ив этом случае для такого класса-потомка мы сможем создавать его экземпляры, или он реализует не все абстрактные методы базового класса (в этом случае он остается тоже абстрактным классом и единственная возможность его использования — производить от него классы-потомки). Статические функции |