Глава 17
В этой главе...
Позвольте огласить две новости: одну хорошую, другую не очень. Хорошая состоит в
том, что все основные идеи, изложенные в этой главе, довольно просты: вы научитесь создавать классы настолько быстро, насколько это возможно. Более того, каждый раз, когда вы использовали при написании программы встроенные функции .NET, в действительности вы использовали классы (так что некоторый опыт работы с классами у вас уже есть).
Новость похуже заключается в том, что для того, чтобы научиться создавать правильно организованные классы, нужно потратить немало времени и усилий. Именно поэтому большинству программистов, которые только начинают осваивать азы объектно-ориентированного программирования, приходится по нескольку раз возвращаться к уже созданным классам, чтобы внести в них дополнительные изменения или вообще переписать их заново.
Вверх
Классы являются фундаментальной составляющей объектно-ориентированного программирования (ООП). Класс — это структура, содержащая в себе некоторые данные и функции, предназначенные для обработки этих данных. Когда кто-то говорит о создании объектов, на самом деле он имеет в виду создание классов. Классы помогают моделировать состояние и поведение различных объектов реального мира. Они же значительно упрощают процесс написания и тестирования больших сложных программ. Кроме того, они предоставляют возможность наследования, что позволяет повторно использовать ранее написанные коды (это не просто удобно — это экономит массу времени и усилий).
Поскольку один класс объединяет в себе данные и функции, которые эти данные обрабатывают, понять, как работает тот или иной объект, довольно просто. По крайней мере проще, чем разобраться в кодах программы, где данные и функции разбросаны в произвольном порядке. Используя классы, вы можете не беспокоиться о том, какую библиотеку нужно подключить, чтобы передвигать картинку по экрану, или как найти домашний телефон сотрудника, занесенного в базу данных. Все это содержится в объекте. В идеале объект должен включать в себя все функции, необходимые для обработки содержащихся в нем данных.
Предположим, например, что у вас есть класс LineObject и вам нужно определить координаты линии или отобразить эту линию на экране. Обе функции должны содержаться в этом же классе, поскольку они оперируют с данными этого класса. Следовательно, вам не придется просматривать коды всей остальной программы в поисках нужных данных или кодов, которые эти данные могут как-то изменить или обработать.
Изменить данные, содержащиеся в классе, или способы их обработки возможно только
И в заключение отметим, что правильно организованные классы избавляют пользователя от необходимости вникать во все технические детали. Программист, который использует готовый класс, не должен знать, как именно сохраняются в нем данные и какие алгоритмы делают этот класс рабочим. Нужно только знать, как таким объектом можно манипулировать.
Например, чтобы определить координаты линии, для хранения которых используется класс
LineObject, можно просто вызвать функцию Initialize. Таким образом программисту, который использует этот класс, требуется всего лишь вызвать эту функцию и совершенно не нужно разбираться, какие при этом будут задействованы переменные или как именно будет использована функция Console.
Сюрприз! Если вы читали предыдущие главы и повторяли приведенные там примеры,
значит, вы уже создали целую обойму классов. Это именно так, поскольку создание классов и создание структур — по сути, одно и то же (а структуры вы создавали уже не раз). Единственное отличие между классами и структурами в том, что классы включают в себя функции, а структуры — нет.
В этом разделе вы найдете все, что нужно знать для создания полноценных классов. Вы узнаете, что такое члены данных и функции-члены, как объявить класс и как ограничить доступ к отдельным его элементам, а также каким образом объявляются функции-члены.
Вверх
Переменные, которые принадлежат какому-то классу, официально называются членами
Например, цвет, размер, цена, форма, вес, имя, исполнитель, продолжительность — это характеристики, которые могут описывать объект. Всю эту информацию можно сохранить как значения переменных и использовать в качестве членов данных различных классов.
Функции-члены являются составной частью классов и используются для обработки хра
Вверх
Для объявления классов используется ключевое слово class:
Предположим, вам нужно создать класс LineObject, За основу можете взять структуру PointList (она использовалась в качестве примера в предыдущих главах), добавив к ней функции и некоторые новые переменные:
Позже вы сможете определить, какие действия выполняют функции Initialize и Draw.
Вверх
Вы можете защитить элементы данных отдельных классов от внешнего воздействия, сделав их закрытыми для всей остальной программы. Доступ к таким элементам данных имеют только функции-члены того же класса.
О том, что в классе LineObject есть такие переменные, как m_nXFrom, m_nYFroin,
Как вы смогли убедиться на примере объявления класса LineObject, ограничить доступ к членам данных очень просто. После того как вы объявили открытые члены данных и функции-члены (использовав для этого ключевое слово public), наберите ключевое слово private. Затем перечислите закрытые члены данных, которые предназначены для использования исключительно внутри данного класса. (Можно создать также закрытые функции-члены. Они могут быть вызваны только другими функциями-членами этого же класса. По сути, это будут вспомогательные функции для открытых функций-членов, действия и возвращаемые результаты которых тем не менее не предназначаются для непосредственного использования за пределами этого класса.)
Совет:
До настоящего времени вы сталкивались только с двумя ключевыми словами, регулирующими права доступа: public и private . Члены данных и функции-члены, объявленные после слова public , являются открытыми (т.е. они могут быть использованы за пределами класса, в котором объявляются). Открытые члены данных и функции-члены создают внешний интерфейс класса. В свою очередь, внешний интерфейс — это то, к чему обращаются при использовании класса.
Закрытые члены данных и функции-члены (они объявляются после слова public) предназначены для внутреннего использования. Такие функции-члены не могут быть вызваны кодами, набранными вне данного класса. Точно так же значения членов данных с ограниченным доступом не могут быть прочитаны или изменены за пределами своего класса.
Использование закрытых членов данных и функций-членов позволяет создавать сложные классы с простым внешним интерфейсом. Это достигается благодаря тому, что доступ ко всем сложным вычислительным процессам, происходящим внутри класса, ограничивается и они становятся невидимыми для пользователей.
Права доступа регулируются еше одним ключевым словом— protected. Члены данных и функиии-члены, объявленные после этого слова, могут быть использованы только функциями-членами этого же класса либо функциями-членами классов, производных от данного класса.
Вверх
После того как вы объявите, из чего состоит класс, можно приступить к определению того, какие именно действия будут выполнять функции-члены. Функции-члены определяются почти точно так же как и обычные функции (что было описано в главе 32). Но, поскольку функция-член является составной частью какого-то определенного класса, указывать нужно как имя функции, так и имя этого класса. (В конце концов, ведь несколько разных классов могут иметь, например, функцию Initialize.)
Чтобы определить функцию-член, наберите имя ее класса, далее два двоеточия (::) и затем имя самой функции. Эти два двоеточия называются квалифицирующим оператором. Этот оператор означает, что указанная функция-член (или член данных) является частью указанного класса. Например, код LineObject: : Draw указывает на функцию-член Draw класса LineObject, а код LineObject: :m_nXFroin ссылается на член данных m_nXFrom этого же класса.
Ниже приведен код, которым определяется функция-член Draw класса LineObject. Эта
Обратите внимание, что при вызове функции DrawLine вам не нужно набирать
После того как вы объявили класс и определили его функции, можно приступить к его использованию. Как и в случае со структурами, классы могут создаваться либо статически, либо динамически.
Вверх
Классы — это те же структуры данных. Если нужно получить доступ к значению, сохраненному как член данных класса, используйте точку (.). Точно так же можно получить доступ и к функции-члену:
Если вы используете указатель на экземпляр класса, функция вызывается несколько иначе:
Вверх
В главе 14 отмечалось. Что можно использовать классы .NET ArrayList и Stack для хранения любых объектов, для которых включена возможность сборки мусора. Следовательно, если вы создадите класс и активизируете для него возможность сборки мусора, в последующем можно будет использовать ArrayList и Stack для хранения экземпляров этого класса. Это очень удобно, если необходимо работать с произвольными наборами элементов (вспомните набор линий, отображаемых на экране).
Ниже показано, как можно использовать ArrayList для хранения объектов LineObject.
Однако извлечь объект из структуры ArrayList будет немного сложнее. Поскольку в структуру ArrayList может быть записана самая разная информация, ей изначально не известно, как обращаться с каждым отдельным элементом. (Более подробно об этом речь идет в главе 19. Пока же мы просто даем краткий обзор такого явления, как полиморфизм.) Если вы хотите использовать объект, сохраненный с ArrayList, нужно будет сообщить, что собой представляет этот объект.
Предположим, например, что необходимо вызвать функцию-член Draw объекта LineObject, только что сохраненного в структуре ArrayList. Если вы непосредственно обратитесь к этому объекту и попробуете вызвать функцию Draw (как показано ниже), то получите сообщение об ошибке.
Причина в том, что компьютер не знает, что собой представляет элемент структуры ArrayList, к которому вы обращаетесь, и тем более не знает, что у этого элемента есть функция-член Draw. Чтобы объяснить ему, чем является этот элемент, нужно использовать ключевое слово static_cast (в переводе это означает установление статического соответствия). Перед тем как указать на элемент, наберите это слово и за ним в угловых скобках укажите тип элемента. Если вернуться, например, к сохраненному в структуре ArrayList объекту LineObject, то, чтобы вызвать функцию Draw, нужно набрать такой код:
Этот код как бы говорит компьютеру: "Возьми текущий элемент структуры ArrayList, рассматривай его как указатель на объект LineObject и, исходя из этого, вызови функцию Draw, которая является функцией-членом этого объекта".
Но ни в коем случае не набирайте
Другими словами, используйте название объекта, но не самого класса.
При написании кодов функций-членов не нужно набирать точку или символы ->, чтобы
Вверх
Теперь, когда вы имеете общее представление о классах, можно вернуться к программе, отображающей линии на экране, и сделать ее объектно-ориентированной. Всего нужно будет определить два класса. Объекты класса LineObject предназначены для хранения информации о каждой отдельной линии.
С этим классом вы уже встречались ранее. Второй класс, DisplayObject, сохраняет информацию обо всех отображаемых объектах. В частности, он содержит в себе структуру ArrayList, состоящую из объектов LineObject. Также у него есть функции-члены, предназначенные для добавления новых объектов LineObject и для отображения линий на экране.
Одной из наиболее интересных функций этого объекта является функция Draw. Она по
порядку извлекает из списка ArrayList все объекты LineObject и для каждого из них вызывает функцию Draw (ту, которая принадлежит классу LineObject). Таким образом она использует класс LineObject для выполнения всей тяжелой работы.
Сама функция main этой программы очень проста. Она создает новый класс
#include "stdafx.h"
#using
using namespace System;
//Stores line information
//Initialize values for this line object
//Draws the line
//Stores all of the lines to draw
//Initialize the DisplayObject structures
//Add a new object
while (!fFinished)
//Should we add another one?
//Draw all of the lines
// This is the entry point for this application
//Initialize the display object
//Add the lines
//Show the display surface
//Draw the lines
//Free up the graphics surface
//Hang out until the user closes the form
Вверх
При написании программы Draw4 вам не нужно было беспокоиться об освобождении памяти, выделяемой для всех создаваемых объектов. Среда .NET делала
Кроме того, поскольку вы не сможете использовать класс .NET ArrayList, вам придется самостоятельно определить класс, задачей которого будет создание связанного списка для сохранения последовательности объектов. Приведенная ниже программа Draw5 является неуправляемой версией программы Draw4. Она содержит класс LineObjectContainer, предназначенный для создания связанного списка из объектов LineObject:
Обратите внимание, что этот класс содержит в себе функцию-член Delete, предназначенную для освобождения памяти. Эта функция вызывается тогда, когда список, состоящий из объектов LineObject становится более не нужным.
Обратите внимание, что необходимо освобождать память, выделенную как для объекта
Ниже показана неуправляемая версия объектно-ориентированной программы, рисующей
#include "stdafx.h"
//Stores line information
//Initialize values for this line object
//Draws the line. We'll write out the contents
//Class for constructing a linked list
//Clean up the list
poCur = this;
//Stores a linked list of objects
//Initialize the structures
//Adds a new object to the list
//Tie it in
//Returns the next LineObject item
//Find the next line object
//Clean up memory
//Stores all of the lines to draw
//Initialize the DisplayObject structures
//Clean it up
//Add a new object
while (!fFinished)
//Should we add another one?
//Draw all of the lines
//Go through each of the line objects
int _tmain(int argc, _TCHAR* argv[])
//Initialize the display object
//Add the lines
//Draw the lines
//Clean up
return 0;
Вверх
Вы только что увидели, насколько удобно держать члены данных закрытыми от остальной программы и использовать специальные функции для доступа к ним и для изменения их значений. Visual C++ .NET оптимизирует этот процесс, позволяя автоматически создавать функции доступа. (Это такие функции, которые присваивают значения членам данных и считывают их.) Вот как это делается:
Обратите внимание, что для того, чтобы сделать свойство рабочим, нужно будет еще определить функции get и set. Для этого обычно используются закрытые переменные, как показано в приведенном ниже коле.
#include "stdafx.h"
#using
using namespace System;
//This class uses properties for accessors
//Here we implement what will occur when a programmer references
int PointObject::get_Y()
void PointObject::set_X(int i)
void PointObject::set_Y(int i)
//Hang out until the user is finished
// This is the entry point for this application
//Now spit them back
HangOut();
return 0;
Если вы пишете неуправляемую программу, также можно создать подобный эффект наличия свойств у объекта. Для этого можно использовать закрытые члены
Если для какой-то переменной определить только функцию get, она станет доступной
#include "stdafx.h"
//This class uses properties for accessors
//Here we implement what will occur when a programmer references
int PointObject::get_Y()
void PointObject::set_X(int i)
void PointObject::set_Y(int i)
int _tmain(int argc, _TCHAR* argv[])
//Now spit them back
return 0;
Вверх
Если программа состоит из нескольких исходных файлов, вам нужно будет объявить классы в заголовочном файле. Если класс необходимо будет использовать в каком-то исходном файле, наберите в нем директиву #include и укажите название заголовочного файла, который должен быть включен в этот исходный файл.
Вверх
Создавая объектно-ориентированную программу, постоянно учитывайте особенности описываемой ею задачи. Старайтесь создавать объекты, максимально точно
При создании классов придерживайтесь приведенной ниже последовательности действий.
Иногда, чем из меньшего количества элементов состоит класс, тем больше возникает возможностей для его повторного использования. Можете попытаться выделить наиболее общие свойства или характеристики, чтобы на их основе создать базовый класс. Помните, что с помощью возможности наследования можно будет затем построить рабочую среду, максимально отвечающую вашим требованиям.
Назад |
Начало урока |
Вверх |
Вперед
Что такое классы и с чем их едят
путем изменения элементов самого класса. Благодаря этому исключаются такие неприятные ситуации, при которых изменение одной глобальной переменной может нарушить работу всей программы. Используя классы, вы всегда сможете контролировать возможные последствия изменения отдельных переменных или их значений.
Разберемся в деталях
Данные-члены
данных. (В терминологии Visual C++ они также обозначаются как переменные-члены, что, по сути, одно и то же.) Когда вы анализируете реальную проблему и моделируете ее в виде объекта, все то, что как-то описывает ее, представляется как члены данных.
Функции-члены
нящихся там данных. При анализе реальной проблемы все действия, которые можно совершать над объектом, моделируются в виде функций-членов.
Например, в отношении объектов могут быть предприняты такие действия, как настройка цвета, вычисление размеров, определение общей цены, отображение названия трека или исполнителя. Все это может быть смоделировано с помощью функций-членов.
Объявление классов
class ClassName
{
здесь описываются элементы данных и функции-члены, доступные
пользователям этого класса
__gc class LineObject
{
void Draw(Graphics *poG);
int m_nYFrom;
int m_nXTo;
int m_nYTo;
Ограничение доступа
m_nXTo и m_nYTo, известно только функциям-членам Initialize и Draw. Для тех, кто будет просто использовать класс LineObject, эти переменные не существуют. Только функции-члены класса LineObject имеют к ним доступ и могут изменять их значения.
книге, начинайте имена закрытых членов данных символами m_.
Защищенный доступ
Определение функций-членов
функция отображает линию на экране.
viod LineObject::Draw(Graphics *poG)
{
Pen *poPen = new Pen(Color::Red);
//Отображение линии
poG->DrawLine(poPen, m_nXFrcm, nwiYFrom, m_nXTo, m_nYTo);
LineObject::m_nXFrom, поскольку внутри функции-члена не требуется использовать
квалифицирующий оператор (::) при указании на члены данных. Внутри класса принадлежность члена данных к этому классу определяется автоматически. Таким образом, использование названия m_nXFrom внутри функции-члена LineObject::Draw равнозначно использованию кода SongList: :m_nXFrom (SongList— название экземпляра класса LineObject). Также обратите внимание на то, что, поскольку Draw является функцией-членом класса LineObject, она имеет доступ к закрытым членам данных этого класса. (В то же время функции-члены других классов, например Circle::Draw, не могут получить непосредственный доступ к закрытым членам данных класса LineObject.)
Что делать с готовыми классами?
//Статически создаваемый класс
Обычно классы создаются динамически. (Классы .NET CLR всегда создаются динамически.)
LineObject oFoo;
//Динамически создаваемый класс
LineObject *poBar = new SongList;
Те же правила и принципы, которые относятся к статическим и динамическим перемен
ным, распространяются и на статические и динамические классы. Создание классов обычно называют созданием экземпляров классов или созданием объектов.
Доступ к элементам класса
//Вызов функции Draw класса LineObject
LineObject oFirst;
oFirst.Exaw();
LineObject *poFirst = new LineObject();
Подобно переменным, экземпляры классов (или объекты) имеют свое имя и тип.
poFirst->Draw();
Статическое соответствие
LineObject *poLine = new LineObject();
ArrayList *paLines = new ArrayList();
//Сохранение объекта LineObject в структуре ArrayList
paLine->Add (poLine) ;
(poEnumerator->Current)->Draw(poG);
static__cast
Если нужно сослаться на функцию-член Draw объекта oFirst , который является
экземпляром класса LineObject, наберите код
oFirst.Draw()
LineObject.Draw()
Имена, используемые функциями-членами
получить доступ к членам данных или к другим функциям-членам этого же объекта. Сама функция принадлежит объекту, поэтому на нее распространяется область видимости других элементов этого объекта. Следовательно, если внутри данного объекта объявлено имя х, любая функция-член может просто ссылаться на это имя.
Немного практики
gc class LineObject
{
void Draw(Graphics *poG);
int m_nYFrom;
int m_nXTo;
int m_nYTo;
gc class DisplayObject
{
void Draw(Graphics *poG);
void Initialize();
//Отображение всех линий на экране
void DisplayObject::Draw(Graphics *poG)
{
IEnumerator *poEnumerator = m_paLines->GetEnumerator();
while (poEnumerator->MoveNext())
{
static_cast(LineObject* poEnumerator->Current)->Draw(poG);
DisplayObject, инициализирует его, и вызывает метод Draw. Итак, вся программа выглядит следующим образом:
// Draw4
// Introduces class structures
#using
#using
#using
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Collections;
__gc class LineObject
{
void Initialize();
void Draw(Graphics *poG);
private:
int m_nXFrom;
int m_nYFrom;
int m_nXTo;
int m_nYTo;
void LineObject::Initialize()
{
Console::WriteLine(S"What is the starting x position?");
m_nXFrom = Int32::Parse(Console::ReadLine());
Console::WriteLine(S"What is the starting y position?");
m_nYFrom = Int32::Parse(Console::ReadLine());
Console::WriteLine(S"What is the ending x position?");
m_nXTo = Int32::Parse(Console::ReadLine());
Console::WriteLine(S"What is the ending y position?");
m_nYTo = Int32::Parse(Console::ReadLine());
void LineObject::Draw(Graphics *poG)
{
Pen *poPen = new Pen(Color::Red);
//Draw the line
poG->DrawLine(poPen, m_nXFrom, m_nYFrom, m_nXTo, m_nYTo);
__gc class DisplayObject
{
void Add();
void Draw(Graphics *poG);
void Initialize();
private:
ArrayList *m_paLines;
void DisplayObject::Initialize()
{
void DisplayObject::Add()
{
String *pszMore;
{
LineObject *poLine = new LineObject();
//Initialize it
poLine->Initialize();
//Store it in the structure
m_paLines->Add(poLine);
Console::WriteLine("Hit y to enter a new line");
pszMore = Console::ReadLine();
if (!pszMore->Equals(S"y"))
{
void DisplayObject::Draw(Graphics *poG)
{
IEnumerator *poEnumerator = m_paLines->GetEnumerator();
while (poEnumerator->MoveNext())
{
static_cast
#ifdef _UNICODE
int wmain(void)
#else
int main(void)
#endif
{
Form *poForm = new Form();
Graphics *poGraphics = poForm->CreateGraphics();
DisplayObject *poDisplay = new DisplayObject();
poDisplay->Initialize();
poDisplay->Add();
poForm->Show();
poDisplay->Draw(poGraphics);
poGraphics->Dispose();
Application::Run(poForm);
Управление памятью в неуправляемых программах
это автоматически. Если вы создаете аналогичную неуправляемую программу
(используя обычный C++), вам придется самим позаботиться о том, чтобы динамически выделяемая память по завершении выполнения программы была освобождена. Сделать это можно путем создания для каждого класса функции-члена
Delete. (Другой возможный вариант рассматривается в главе 18.)
//Класс, представляющий отдельный элемент связанного списка
c l a s s LineObjectContainer
{
LineObjееt *poLine;
LineObjectContainer *poNext;
void Delete();
Поскольку класс LineObjectContainer использует для хранения информации связан-
ный список, функция Delete находит каждый элемент этого списка и освобождает выделенную для него память:
//Освобождение памяти, выделенной для всего списка
void LineObjectContainer::Delete()
{
poCur = this;
while (poCur|
{
//Освобождение памяти, выделенной для объекта LineObject
delete poCur->poLine;
poCur = poCur->poNext;
//Освобождение памяти, выделенной
//для объекта LineObjectContainer
delete poTemp;
LineObject (предназначен для хранения информации о координатах линии), так и для объ-
екта LineObjectContainer (предназначен для создания связанного списка из объектов
LineObject).
на экране линии. Поскольку здесь не могут быть использованы возможности .NET, автоматически создающие связанные списки и освобождающие динамически выделяемую память, неуправляемая версия будет несколько сложнее, чем управляемая.
// Draw5
// Introduces class structures
// Unmanaged
#include
class LineObject
{
void Initialize();
void Draw();
private:
int m_nXFrom;
int m_nYFrom;
int m_nXTo;
int m_nYTo;
void LineObject::Initialize()
{
cout << "What is the starting x position?";
cin >> m_nXFrom;
cout << "What is the starting y position?";
cin >> m_nYFrom;
cout << "What is the ending x position?";
cin >> m_nXTo;
cout << "What is the ending y position?";
cin >> m_nYTo;
void LineObject::Draw()
{
class LineObjectContainer
{
LineObject *poLine;
LineObjectContainer *poNext;
void Delete();
void LineObjectContainer::Delete()
{
while (poCur)
{
//Clear out the line object
delete poCur->poLine;
poCur = poCur->poNext;
//Delete the container object
delete poTemp;
class ArrayList
{
void Add(LineObject *poLine);
LineObject *MoveNext();
void Delete();
void Initialize();
private:
LineObjectContainer *m_poFirst;
LineObjectContainer *m_poCur;
LineObjectContainer *m_poLast;
void ArrayList::Initialize()
{
m_poCur = 0;
m_poLast = 0;
void ArrayList::Add(LineObject *poLine)
{
LineObjectContainer *poLOC = new LineObjectContainer();
//Set its value
poLOC->poLine = poLine;
poLOC->poNext = 0;
if (!m_poFirst)
{
m_poCur = m_poFirst;
else
m_poLast->poNext = poLOC;
//Advance the end pointer
m_poLast = poLOC;
LineObject *ArrayList::MoveNext()
{
//If there are no items, just return null
if (!m_poCur)
return 0;
poNext = m_poCur->poLine;
//Advance the pointer
m_poCur = m_poCur->poNext;
return poNext;
void ArrayList::Delete()
{
m_poFirst->Delete();
class DisplayObject
{
void Add();
void Draw();
void Initialize();
void Delete();
private:
ArrayList *m_paLines;
void DisplayObject::Initialize()
{
m_paLines->Initialize();
void DisplayObject::Delete()
{
void DisplayObject::Add()
{
char cMore;
{
LineObject *poLine = new LineObject();
//Initialize it
poLine->Initialize();
//Store it in the structure
m_paLines->Add(poLine);
cout << "Hit y to enter a new line" << endl;
cin >> cMore;
if (cMore != 'y')
{
void DisplayObject::Draw()
{
while (poLine = m_paLines->MoveNext())
{
poLine->Draw();
{
DisplayObject *poDisplay = new DisplayObject();
poDisplay->Initialize();
poDisplay->Add();
poDisplay->Draw();
poDisplay->Delete();
delete poDisplay;
Функции доступа
Этот код говорит о том, что у объекта есть свойство X. Если нужно прочитать значение этого свойства, можно вызвать функцию get_X () или набрать такой код:
property int get_X();
property void ser:__X(int i) ;
n = foo.X;
Если же нужно присвоить свойству X какое-то значение, можно вызвать функцию
set_X() или набрать код
foo.X ~ п;
Если вы объявите только функцию get, свойство станет доступным только для чтения.
// Accessors
// Provides private access functions
__gc class PointObject
{
__property int get_X();
__property void set_X(int i);
__property int get_Y();
__property void set_Y(int i);
private:
int m_nX;
int m_nY;
//the X and Y properties of the object. Note how we use private
//members for storing the real values
int PointObject::get_X()
{
{
{
{
void HangOut()
{
Console::ReadLine();
#ifdef _UNICODE
int wmain(void)
#else
int main(void)
#endif
{
//Set the x and y values
poPoint->X = 3;
poPoint->Y = 2;
Console::WriteLine(S"The point is
{
данных и открытые функции, которые обеспечивают к ним доступ. При этом
нельзя будет ссылаться на сами свойства, как это делается в управляемых программах. Вместо этого нужно будет непосредственно вызывать функции-члены
get и set.
только для чтения.
Ниже приведен код неуправляемой программы, в котором используются функции доступа.
// Accessors2
// Provides private access functions
// Unmanaged
#include
class PointObject
{
int get_X();
void set_X(int i);
int get_Y();
void set_Y(int i);
private:
int m_nX;
int m_nY;
//the X and Y properties of the object. Note how we use private
//members for storing the real values
int PointObject::get_X()
{
{
{
{
{
//Set the x and y values
poPoint->set_X(3);
poPoint->set_Y(2);
cout << "The point is " << poPoint->get_X() << "," << poPoint->get_Y() << endl;
char enterchar;
cout <<"Hit the enter key to stop the program";
cin >>enterchar;
Заголовочные файлы
Если вы добавляете в класс или удаляете из класса члены данных «ли функции-члены, не забудьте обновить заголовочный файл. В противном случае вы получите сообщение наподобие такого: 'fоо': is not a member of 'baz '. Расшифровывается оно приблизительно так: "Вы забыли обновить заголовочный файл для того, чтобы функция f o o была включена в класс baz". Или так: "Вы указали неверный параметр, т.е. то, что было перечислено при объявлении класса, не совпадает с тем, на что вы ссылаетесь при его использовании".
Общие рекомендации
отображающие те элементы, которые присутствуют в модели. (Например, если
создается объектно-ориентированная программа, моделирующая работу музыкального автомата, нужно создать объект, представляющий сам музыкальный автомат, и объект, представляющий список воспроизводимых записей.)
Для управления объектом используйте функции высокого уровня, так чтобы пользователь не знал, например, что имена сохраняются в массиве или что записи извлекаются из связного списка.
Что это за данные? Как вы будете их обрабатывать?
Приведем некоторые общие рекомендации, которыми следует руководствоваться приступая к проектированию классов.
для себя много удачных решений.
программы или в тех программах, которые вы будете создавать в будущем.
единое целое. Другими словами проверьте, есть ли в программе такие фрагменты
данных, которые до использования ООП обрабатывались сразу многими процедурами. Именно из них можно создавать хорошие классы. Предположим, например, что у вас есть структура, предназначенная для хранения информации о сотрудниках, и есть набор различных процедур, вычисляющих размеры начисленной заработной платы, количество предоставленных отгулов и т.п. Все это можно объединить для создания класса, управляющего информацией о сотрудниках.
снова с небольшими вариациями, создайте базовый класс для представления
этих характеристик.
хранения информации о продолжительности музыкальных записей. Пользователь этого объекта должен иметь возможность найти интересующие его данные, не вникая в то, что для их хранения используется массив. В объекте должна быть функция-член, которая сама найдет нужное значение и вернет его в качестве результата. Такая практика значительно упрощает работу с объектами.
Не бойтесь перечеркнуть все сделанное ранее и начать заново: все через это
проходят. Воспринимайте это просто как часть образовательного процесса.
Содержание