ООП на С++ примерах

Автор: | 05.02.2018

Введение в классы
Перегружаемые функции и операторы
Встраиваемые функции
Конструкторы и деструкторы
Обмен данными между объектами и приложением
Указатели и ссылки на объекты
Наследование в языке С++
Виртуальные функции
Динамическое управление памятью
Тестовые примеры

Введение в классы

Класс– это механизм для создания новых типов. Синтаксис описания класса похож на синтаксис описания структуры. В отличие от структур в языке СИ членами структуры в языке С++ кроме переменных могут быть и функции. В С++ для создания структуры (класса) традиционно принято использовать ключевое слово class, но допускается использовать и struct.

struct _3d
{
// public по умолчанию
double mod (); //объяв_ся функция mod
double projection (_3d r);
private: // модификатор доступа
double x, y, z;
};
class _3d
{
double x, y, z; // private по умолчанию
public:  // модификатор доступа
double mod ();
double projection (_3d r);
};

Функции объявлены при описании класса, но они еще не определены.

double _3d::mod ()             // определение функции mod класса _3d
{ return x + y +z;}
double _3d::projection (_3d r) // объект r класса _3d
{return x + r.mod();}          //вызывается метод (функция) mod объекта r

Запуск программы с использованием переменных и функций созданного типа

#include <iostream>
using namespace std;
void main()
{
_3d a, b;             //объявляются объекты a и b класса _3d
a.x=1; a.y=1; a.z=1; //инициализация свойств объектов a и b
b.x=2; b.y=2; b.z=2;
double dPro, dMod;
dMod = a.mod();          //вызывается функция mod объекта a
dPro = b.projection(a); //вызывается функция projection(a) объекта b
cout << dMod << "\n";
cout << dPro << "\n";
}

В этой и последующих обучающих программах есть ошибки, которые необходимо определить и исправить при отладке программы. Нахождение ошибок способствует усвоению материала


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

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

Прочитайте код программы, используя терминологию программиста (см. комментарии к программе).

Перегружаемые функции и операторы

Транслятор С++ различает функции не только по именам, но и по типу аргументов. В языке С++ можно «перегрузить» одно имя для трех типов данных.

int abs (int x) { return x<0 ? -x : x; } // определение функции 1
long abs (long x) { return x<0 ? -x : x; } // определение функции 2
double abs (double x) { return x<0 ? -x : x; } // определение функции 3

#include <iostream>
using namespace std;main()
{
cout << abs(-1000) << "\n"; // вызов функции 1
cout << abs(-1000L) << "\n"; // вызов функции 2
cout << abs(-1000.0) << "\n"; // вызов функции 3
}

Одно из основных применений перегрузки функций – это достижение полиморфизма, что воплощает в себе философию «один интерфейс, множество методов«.

В языке VLISP нет различия между операциями и функциями. Операции в C\C++ также можно воспринимать как функции, которые отличаются лишь синтаксисом выражения. Язык С++ позволяет перегружать и операции.

Многие из операций выполняются над различными типами переменных – бесформатный ввод-вывод (<< и >>) или математические операции (+, -) и т. д. Пример:

int i1, i2, i3;
long int l1, l2, l3;
double f1, f2, f3;
i1 = i2 + i3;
l1 = l2 + l3;
f1 = f2 + f3;

Пример перегрузки оператора «+» на действия с векторами:

struct _3d   // описание класса _3d
{
double x, y, z; // координаты
_3d operator + (_3d); // объяв-ся ф-я “operator +” c пар-м типа _3d и возвр. объект класса _3d
};
_3d _3d::operator + (_3d b) // опред-ся ф-я “operator +” класса _3d
{
_3d c;            
c.x = x + b.x;
c.y = y + b.y;
c.z = z + b.z;
return c;
}
#include <iostream>
using namespace std;
void main()
{
_3d A, B, C;
A.x = 1.0;
A.y = 2.0;
A.z = 3.0;
B = A;
C = A + B; // тоже самое  C = A.operator + (B); выз-ся ф-я "operator +" объекта A c пар_м B
cout << C.x <<"\n"<< C.y <<"\n"<<C.z <<"\n";
}

Прочитайте код программы, используя терминологию программиста (см. комментарии к программе).

Встраиваемые функции

Встраиваемые функции рассмотрим на следующем примере фрагмента программы:

struct _3d
{
double mod (){return x + y +z;}; // 1-й способ встраивания (ф-я определена в классе)
double projection (_3d r);
private:
double x, y, z;
};

inline double _3d::projection (_3d r) // 2-й способ встраивания (ключевое слово inline)
{
return x + r.mod();
}


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

Кроме этого, inline функции обеспечивают более стройный способ встраивания в программу короткой функции (см. 1-й способ встраивания). Также, компилятор С++ гораздо лучше работает со встраиваемыми функциями, чем с директивами препроцессора и другими макроопределениями.

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

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

Деструктор – метод, который вызывается автоматически при уничтожении объекта.

Для обоих имя совпадает с именем класса (для деструктора добавляется ~).

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

struct _3d
{
double mod ( ) {return x ;};
_3d( ) {x=5;} // конструктор
~_3d( ){cout << "Destructor";}
private:
double x;
};

main()
{
_3d A;   // объявление объекта A и вызов конструктора _3d()
cout << A.mod()<<"\n";
}        // уничтожение объекта A и вызов деструктора ~_3d()

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

5
Destructor

В классе может быть определено несколько конструкторов. Конструкторы могут иметь параметры. Пример:

class _3d
{
double x, y, z;
public:
double mod ( ) {return x ;};
_3d() { x=y=z=0;}
_3d (double initX, double initY, double initZ) { x = initX; y = initY; z = initZ; }
};

main()
{
_3d A; // A.x = A.y = A.z = 0;
_3d B (3,4,0); // B.x = 3.0, B.y = 4.0, B.z = 0.0
cout << A.mod()<<"\n";
}

Контрольный вопрос. Еще до запуска программы определите, что выведется на печать?

Добавьте недостающие элементы программы и запустите ее

Обмен данными между объектами и приложением

Обращение к закрытым переменным через открытые методы наподобие PublicMethod() входит в число стандартных приемов программирования; тем самым удается ограничить доступ к закрытым данным класса. Пример:

#include <iostream>
using namespace std;

class DataClass
{
private:
int PrivateDataMember;  // закрытая переменная
public:
DataClass(int Value);
int PublicDataMember;
int PublicMethod(void); // открытый метод
};

DataClass::DataClass(int Value)
{
PrivateDataMember = Value;
}

int DataClass::PublicMethod(void)
{
return PrivateDataMember;
}

void main()
{
DataClass DataObject(1);
DataObject.PublicDataMember = 2;
cout << "DataObject.PublicDataMember = " << DataObject.PublicDataMember << "\n";
cout << "DataObject.PrivateDataMember = " << DataObject.PublicMethod() << "\n";
}


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

Контрольное задание. Соблюдая терминологию прочитайте последовательно программу от инициализации переменной PrivateDataMember до ее вывода на печать.

Указатели и ссылки на объекты

Доступ к членам объекта можно осуществлять и через указатель на объект. В этом случае применяется операция стрелка «->».

main()
{
_3d A (2,3,4);
_3d *pA;
pA = &A;
cout << pA->mod()<<'\n'; // вызывается функция mod объекта, на который указывает указатель pa
}

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

class ClassName
{
public:
ClassName (){cout << "Constructor \n";}
~ClassName (){cout << "Destructor \n";}
};
void f (ClassName o) {cout << "Function \n";}
main()
{
ClassName c1;
f (c1);
}

Эта программа напечатает следующее:

Constructor
Function
Destructor
Destructor

Конструктор вызывается только один раз. Это происходит при объявлении объекта с1. При передаче объекта c1 функции f(c1) в качестве параметра в памяти создается копия объекта, однако конструктор при этом не вызывается.  Деструктор же  в программе вызывается дважды — один раз для копии, второй раз для самого объекта c1.

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

Параметр-указатель

void ToZero (_3d *vec)
{
vec->set (0,0,0); // используется " -> "
}

main()
{
_3d A (2,3,4);
ToZero (&A);
}
Параметр-ссылка

void ToZero (_3d &vec)
{
vec.set (0,0,0); // используется "."
}

main()
{
_3d A (2,3,4);
ToZero (A);
}

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

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

Контрольное задание: используя фрагмент программы (с указателями) довести ее  до рабочего состояния с описанием класса _3D и выводом в окно консоли значение какой-либо переменной. При этом все функции и переменные поместить в описание класса _3D. Переменные сначала описать в классе открытыми (Public). Затем задание усложняется —  переменные  описать в классе закрытыми (Private)


Ссылки на объект могут также использоваться в качестве возвращаемого значения функции. Обычно такой механизм применяется в сочетании с указателем this. Рассмотрим пример перегрузки  оператора «=»:

_3d& _3d::operator = (_3d &b)  // Прочитайте этот рядок
{
x = b.x;
y = b.y;
z = b.z;
return *this;
}

Возвращаемый результат этой функции будет тот объект, который вызывал операцию «=».

Наследование в языке С++

Пример 1:

#include <iostream>
using namespace std;

class vehicle {
public: void start();
void move();
};

class helicopter : public vehicle { // описывается класс, производный от базового
public: void move();           
};

void vehicle::start() { cout << "Starting...\n";}
void vehicle::move() { cout << "Driving...\n";}     // определяется метод move()
void helicopter::move() { cout << "Flying...\n";}  // переопределяется метод move() в производном классе

void main()
{
helicopter whirly;
whirly.start();
whirly.move(); // выводится "Flying", а не "Driving"
}

В этой программе демонстрируется основное правило наследования «не нашел у себя, можешь позаимствовать у отца».  При вызове whirly.start() функция была позаимствована у «отца» (базовом классе), а функция whirly.move() была переопределена в производном классе. Какая из 2-х функций move() вызывается, определяется по имени объекта, к которому она отнесена. Здесь мы вновь сталкиваемся с перегрузкой функций.

Пример 2:

#include <iostream>
using namespace std;

class BaseClass
{
public:
BaseClass() {cout << "Base class constructor \n";}
~BaseClass() {cout << "Base class destructor \n";}
};

class DerivedClass: public BaseClass // public – модификатор наследования
{
public:
DerivedClass() {cout << "The constructor of the derived class \n";}
~DerivedClass() {cout << "The destructor of the derived class \n";}
};

main()
{
DerivedClass obj;
}

Эта программа выводит сообщения в  следующей последовательности:

Base class constructor
The constructor of the derived class
The destructor of the derived class
Base class destructor

Модификатор наследования (public, protected или private) определяет, какие права доступа к переменным и методам класса-родителя будут «делегированы» классу-потомку.  Protected эквивалентен private с единственным исключением: protected члены базового класса доступны для членов всех производных классов.

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

#include <iostream>
using namespace std;

class BaseClass
{
int j, i;
public:
BaseClass (int jj, int ii)  // 2. Конструктор базового класса
{
j=jj; i=ii;
cout << j << "\n" << i << "\n";
}
};

class DerivedClass: public BaseClass
{
int n;
public:
DerivedClass (int nn);
};

DerivedClass :: DerivedClass (int nn): BaseClass (nn/2, nn%2)  // 3. Конструктор производного класса
{ n=nn; }

main()
{
DerivedClass obj(15);  // 1. Объявляется объект производного класса 
}

В результате работы программы на экран выведутся числа 7 и 1.

На этом этапе обучения обычно возникают сложности с правильным чтением программы, поскольку накопилось слишком много синтаксических особенностей, которые сложно различать новичкам. «Пирамидка знаний» еще неустойчива и как бы «рассыпается».  Нужно проявить упорство и успех придет.

Программа читается в последовательности, указанной пунктами:  1, 2, 3. После объявления объекта (1) вызывается конструктор базового класса (2), а потом производного (3). Передача 2-х параметров конструктору базового класса обусловлена синтаксисом определения конструктора базового класса (3)

Виртуальные функции

Ниже рассмотрен пример наследования класса Circle от класса Point.

//Объявление enum
//задает тип переменной перечисления и
//определяет список именованных констант
enum Boolean {false, true};
// false = 0, true = 1
class Point
{
protected:
int X;
int Y;
Boolean Visible;
public:
Point (const Point& cp);
Point (int newX =0, int new Y =0);
void Show();
void Hide();
void MoveTo(int newX, int newY);
};

void Point::Show()
{
Visible = true;
putpixel (X,Y,getcolor());
}

void Point::Hide()
{
Visible = false;
putpixel (X,Y,getbkcolor());
}
void Point::MoveTo (int newX, int newY)
{
Hide ();
X = newX;
Y = newY;
Show ();
}
main()
{
int graphDr = DETECT, graphMode;
initgraph ( &graphDr, &graphMode, "");
Point pointA (50,50);
pointA.Show ();
pointA.MoveTo (100,130);
pointA.Hide ();
closegraph();
}


class Circle: public Point
{
int Radius; // private по умолчанию
public:
Circle (int initX, int initY,
 int initR);
void Show ();
void Hide ();
void MoveTo (int newX, int newY);
};

Circle::Circle (int initX, int initY,
 int initR)
:Point (initX, initY)
{
Radius = initR;
}

void Circle::Show ()
{
Visible = true;
circle (X,Y, Radius);
}

void Circle::Hide ()
{
Visible = false;
unsigned int tempColor = getcolor ();
setcolor (getbkcolor());
circle (X,Y, Radius);
setcolor (tempColor);
}
void Circle::MoveTo (int newX, 
int newY)
{
Hide ();
X = newX;
Y = newY;
Show ();
}
main()
{
int graphDr = DETECT, graphMode;
initgraph ( &graphDr, &graphMode, "");
Circle C (150,200,50);
C.Show();
C.MoveTo (300,100);
getch();
closegraph();
}

Обратите внимание на одинаковые по содержанию функции (методы).

void Point::MoveTo (int newX, int newY) //функция отца
void Circle::MoveTo (int newX, int newY) //функция сына

Уберем вторую из программы, ведь есть правило «не нашел у себя, можешь позаимствовать у отца». Тогда обращение к функции через объект производного класса C.MoveTo (300,100) вызовет функцию базового класса Point::MoveTo (int newX, int newY), а из нее запустятся функции Point::Hide() и Point::Show() в соответствии с тем же правилом. Однако такое правило в этой ситуации не подходит. По логике программы необходимо, чтобы из функции отца Point::MoveTo (int newX, int newY) запустились функции сына Circle::Hide() и Circle::Show(). Как решить эту проблему? Необходимо объявить эти функции виртуальными в обоих классах:

virtual void Hide ();
virtual void Show ();

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

Теперь, из функции отца Point::MoveTo (int newX, int newY) будут вызываться виртуальные функции производного класса Circle::Hide() и Circle::Show(), если было обращение к функции MoveTo реализуется через объект производного класса: C.MoveTo (300,100) . В случае обращения к функции MoveTo через объект базового класса pointA.MoveTo (300,100) из функции отца Point::MoveTo (int newX, int newY) будут вызываться виртуальные функции базового класса Point::Hide() и Point::Show() 

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

Для чего нужны виртуальные функции? Их применение, отнюдь, не ограничивается экономией программного кода, как в рассмотренном примере. Наиболее широко механизм виртуальных функций используется в подключаемых к программе библиотеках классов, например — библиотеке  MFC (MicrosoftFoundationClasses).  Из методов MFC классов часто предусматривается вызов функций, которые еще не определены. Они определяются в создаваемых программистом производных классах.

Динамическое управление памятью

В программе на языке Си память динамически выделяется функциями malloc и calloc. Функция free (p) освобождает область памяти, на которую ссылается указатель p. Но при создании объекта в С++ используется конструктор. А функция malloc (), разработанная задолго до появления на свет С++, понятия не имеет о конструкторах.

В  языке С++ для выделения памяти используется оператор new , который не только выделяет память, но и вызывает соответствующий конструктор:

CStatic* MyStatic; // Указатель на объект надпись
MyStatic = new CStatic();
if (MyStatic!=NULL) MyStatic->Create("MyStatic",WS_CHILD|WS_VISIBLE|SS_CENTER,
CRect(10,10,100,50),this);

Параметры, указанные после имени объекта, передаются конструктору.

Когда необходимость в объекте, созданном оператором new, отпадет, освободиться от него можно с помощью оператора delete.

if (MyStatic!=NULL) delete MyStatic; // удалить динамический объект

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

Тестовые примеры

Ниже приводятся программы и фрагменты программ. Для тестового примера необходимо определить задачу, выполняемую программой в целом и каждой строкой в отдельности, знать последовательность обращения к операторам, а также уметь правильно комментировать назначение элементов языка, используемых в программном коде. Чтение строк обычно начинается со слов «объявляется, определяется, вызывается, инициализируется …» и т.п.

Пример 1:

struct _3d
{
double mod ();
double projection (_3d r);
private:
double x, y, z;
};

double _3d::mod ()
{
return x + y +z;
}

double _3d::projection (_3d r)
{
return x + r.mod();
}

#include <iostream>
using namespace std;

void main()
{
_3d a, b;
a.x=1; a.y=1; a.z=1;
b.x=2; b.y=2; b.z=2;
double dPro, dMod;
dMod = a.mod();
dPro = b.projection(a);
cout << dMod << "\n";
cout << dPro << "\n";
}

Пример 2:

int abs (int x) { return x<0 ? -x : x; }
long abs (long x) { return x<0 ? -x : x; }
double abs (double x) { return x<0 ? -x : x; }

#include <iostream.h>
main()
{
cout << abs(- 1000 ) << "\n";
cout << abs(- 1000L ) << "\n";
cout << abs(- 1000.0 ) << "\n";
}

Пример 3:

struct _3d
{
double x, y, z; // координаты
_3d operator + (_3d);
};

_3d _3d:: operator + (_3d b)
{
_3d c;
c.x = x + b.x;
c.y = y + b.y;
c.z = z + b.z;
return c;
}

#include <iostream>
using namespace std;

void main()
{
_3d A, B, C;
A.x = 1.0;
A.y = 2.0;
A.z = 3.0;
B = A;
C = A + B;
cout << C.x <<"\n"<< C.y <<"\n"<<C.z <<"\n";
}

Пример 4:

struct _3d
{
double mod () {return x + y +z;} ;
double projection (_3d r);
private:
double x, y, z;
};

inline double _3d::projection (_3d r)
{
return x + r.mod();
}

Пример 5:

struct _3d
{
double mod ( ) {return x ;};
_3d( ) {x=5;}
~_3d( ){cout << "End";}
private:
double x;
};

main()
{
_3d A;
cout << A.mod()<<"\n";
}

Пример 6:

struct _3d
{
double mod ( ) {return x;};
void set (double initX) { x = initX;}
private:
double x;
};

main()
{
_3d A;
A.set (5);
cout << A.mod()<<"\n";
}

Пример 7:

class _3d
{
double x, y, z;
public:
double mod ( ) {return x;};
_3d() { x=y=z=0;}
_3d (double initX, double initY, double initZ) { x = initX; y = initY; z = initZ; }
};

main()
{
_3d A;
_3d B (3,4,0);
cout << A.mod()<<"\n";
}

Пример 8:

#include <iostream>
using namespace std;

class DataClass
{
private:
int PrivateDataMember;
public:
DataClass(int Value);
int PublicDataMember;
int PublicMethod(void);
};

DataClass::DataClass(int Value)
{
PrivateDataMember = Value;
}

int DataClass::PublicMethod(void)
{
return PrivateDataMember;
}
 
void main()
{
DataClass DataObject(1); DataObject.PublicDataMember = 2;
cout << "DataObject.PublicDataMember = " << DataObject.PublicDataMember << "\n";
cout << "DataObject.PrivateDataMember = " << DataObject.PublicMethod() << "\n";
}

Пример 9:

main()
{
_3d A (2,3,4);
_3d *pA;
pA = &A;
cout << pA->mod() <<"\n";
}

Пример 10:

class ClassName
{
public:
ClassName (){cout << "Работа конструктора \n";}
~ClassName (){cout << "Работа деструктора \n";}
};

void f (ClassName o) {cout << "Работа функции f \n";}
main()
{
ClassName c1;
f (c1);
}

Пример 11:

void ToZero (_3d *vec )
{
vec->set (0,0,0);
}

main()
{
_3d A (2,3,4);
ToZero ( &A );
}

 

Пример 12:

void ToZero (_3d &vec )
{
vec.set (0,0,0);
}

main()
{
_3d A (2,3,4);
ToZero ( A );
}

 

Пример 13:

3d& _3d::operator = (_3d &b)
{
x = b.x;
y = b.y;
z = b.z;
return *this;
}

Пример 14:

#include <iostream>
using namespace std;

class BaseClass
{
public:
BaseClass() {cout << "Base class constructor \n";}
~BaseClass() {cout << "Base class destructor \n";}
};

class DerivedClass: public BaseClass // public – модификатор наследования
{
public:
DerivedClass() {cout << "The constructor of the derived class \n";}
~DerivedClass() {cout << "The destructor of the derived class \n";}
};

main()
{
DerivedClass obj;
}

Пример 15:

#include <iostream>
using namespace std;

class BaseClass
{
int j, i;
public:
BaseClass (int jj, int ii)
{ j=jj; i=ii; cout << j << "\n" << i << "\n"; }
};

class DerivedClass: public BaseClass
{
int n;
public:
DerivedClass (int nn);
};

DerivedClass :: DerivedClass (int nn): BaseClass (nn/2, nn%2)
{ n=nn; }

main()
{
DerivedClass obj(15);
}

Пример 16:

enum Boolean {false, true};
// false = 0, true = 1
class Point
{
protected:
int X;
int Y;
Boolean Visible;
public:
Point (const Point& cp);
Point (int newX =0, int new Y =0);
void Show();
void Hide();
void MoveTo(int newX, int newY);
};

void Point::Show()
{
Visible = true;
putpixel (X,Y,getcolor());
}

void Point::Hide()
{
Visible = false;
putpixel (X,Y,getbkcolor());
}

void Point::MoveTo (int newX, int newY)
{
Hide ();
X = newX;
Y = newY;
Show ();
}

main()
{
int graphDr = DETECT, graphMode;
initgraph ( &graphDr, &graphMode, "");
Point pointA (50,50);
pointA.Show ();
pointA.MoveTo (100,130);
pointA.Hide ();
closegraph();
}
class Circle: public Point
{
int Radius; // private по умолчанию
public:
Circle (int initX, int initY,
 int initR);
void Show ();
void Hide ();
void MoveTo (int newX, int newY);
};

Circle::Circle 
(int initX, int initY, int initR)
:Point (initX, initY)
{
Radius = initR;
}

void Circle::Show ()
{
Visible = true;
circle (X,Y, Radius);
}

void Circle::Hide ()
{
Visible = false;
unsigned int tempColor = getcolor ();
setcolor (getbkcolor());
circle (X,Y, Radius);
setcolor (tempColor);
}

void Circle::MoveTo 
(int newX, int newY)
{
Hide ();
X = newX;
Y = newY;
Show ();
}

main()
{
int graphDr = DETECT, graphMode;
initgraph ( &graphDr, &graphMode, "");
Circle C (150,200,50);
C.Show();
C.MoveTo (300,100);
getch();
closegraph();
}

Пример 17:

CStatic* MyStatic;
MyStatic = new CStatic();
if (MyStatic!=NULL) MyStatic->Create("MyStatic",WS_CHILD|WS_VISIBLE|SS_CENTER, CRect(10,10,100,50),this);
if (MyStatic!=NULL) delete MyStatic;

Пример 18:

#include <iostream>
using namespace std;

class vehicle {
public: void start();
void move();
};

class helicopter : public vehicle {
public: void move();
};

void vehicle::start() { cout << "Starting...\n";}
void vehicle::move() { cout << "Driving...\n";}
void helicopter::move() { cout << "Flying...\n";}

void main()
{
helicopter whirly;
whirly.start();
whirly.move();
}

Пример 19:

#include <iostream>
using namespace std;
#include <stdio.h>

class TIP
{
public:
int a,b;
virtual f2(int b, int pb);
int *pa, *pb;
TIP(int per);
~TIP();
f1(int a, int pa);
};

class tip1:public TIP{
public:
tip1(int per):TIP(per){ };
f2();
};

TIP::TIP (int per)
{
a = per;
}

TIP::~TIP()
{
printf("Destructor\n");
}

TIP::f1(int a, int pa)
{
printf("a=%d,\n&a=%d\n",a,pa);
}

TIP::f2(int b, int pb)
{
printf("b=%d,\n%&b=%d\n",b,pb);
}

tip1::f2()
{
printf("pro_klassn\n");
}

void main()
{
TIP CC(2);
TIP *pc = &CC; //TIP *pc; pc=&CC;
tip1 CC1(4);
printf("adr_CC=%d\n",pc);
pc->pa = &CC.a;
pc->b = pc->a * 3;
pc->pb = &CC.b;
pc->f1(pc->a,(int)CC.pa);
CC.f2(pc->b,(int)CC.pb);
CC1.b= CC1.a*3;
CC1.pb=&CC1.b;
pc->f2(CC1.b,(int)CC1.pb);
pc =&CC1;
//CC.~TIP();
printf("adr_CC1=%d\n",pc);
//
//pc->f2();
CC1.f2();
//CC1.~tip1();
}

Автор: Николай Свирневский

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *