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

Автор: | 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::Hide() и Point::Show() в соответствии с с тем же правилом “сначала посмотри функцию у себя, если не нашел, то обратись к отцу, но не к сыну”. Однако такое правило в этой ситуации не подходит, по логике программы необходимо, чтобы из функции отца Point::MoveTo (int newX, int newY) запустились функции сына Circle::Hide() и Circle::Show().

Обращение «класса-отца» к функциям «класса-сына» возможно, если объявить эти функции виртуальными в обоих классах.

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

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

Например, при обращении C.MoveTo (300,100) и, отсутствии этого метода в производном классе, будет вызываться функция базового класса, а из нее будут вызываться виртуальные функции Circle::Hide() и Circle::Show() производного класса. Заметьте, что здесь объект C объявлен как объект производного класса.

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

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

В программе на языке Си память динамически выделяется функциями 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 не будет опубликован. Обязательные поля помечены *