Приватные или защитные члены класса
Методология ООП
Модель – абстракция физической системы, просматриваемая с определенной точки зрения и представленная на некотором языке или в графическом виде. С точки зрения принципов системного анализа, одна и та же физическая система может быть представлена разными моделями. А назначение каждой модели для одной и той же системы определяется характером решаемой задачи изучаемой проблемы.
Основное требование к модели программы – она должна быть понятна заказчику программы, пользователю и группе программистов – разработчиков.
Объектно-ориентированное программирование – совокупность технологий, принципов, инструментальных средств, для создания программных систем на основе архитектуры взаимодействия объектов.
Основные принципы ООП:
1) Абстракция
2) Инкапсуляция
3) Наследование
4) Полиморфизм (многообразие)
Пример описания модели:
Class Box
{
Public:
Double H;
Double L;
Double W;
Double volume ()
{return H*L*W;}
};
Абстракция
– характеристика сущности, которая отличает ее от других сущностей. Абстракция определяет границу представления соответствующего объекта модели и применяется для определения таких фундаментальных понятий ООП как класс или объект.
Принцип абстракции гласит, что чем больше атрибутов и операций принимается во внимание, то тем ближе полученная модель будет описывать реальную систему.
Класс представляет собой абстракцию совокупности реальных объектов, которые имеют общий набор свойств и обладают одинаковым поведением.
Объект (в контексте ООП) рассматривается как экземпляр соответствующего класса.
Объекты, которые не имеют идентичных свойств или не обладают одинаковым поведением, по определению не могут быть отнесены к одному классу.
Классы можно организовать в виде иерархической структуры, которая напоминает схему классификации понятий в понятийной логике. В качестве более общего понятия или категории берется понятие, имеющее наибольший объем и наименьшее содержание. Это – самый высокий уровень абстракции для данной иерархии. Затем данное общее понятие конкретизируется, то есть уменьшается его объем и увеличивается его содержание. Появляется менее общее понятие, которое на схеме иерархии будет расположено на уровень ниже исходного. Этот процесс конкретизации понятий может быть продолжен до тех пор, пока на самом нижнем уровне не будет получено понятие, дальнейшая конкретизация которого либо невозможна, либо нецелесообразна.
Принцип, в соответствии с которым знание о наиболее общей категории разрешается применять для более частной категории, называется наследованием. Наследование тесно связано с иерархией классов, определяющей, какие классы следует считать наиболее абстрактными и общими по отношению к другим классам. Наиболее общий или абстрактный класс, будем называть базовым или родительским классом, или классом – предком. А частный случай от родительского класса будем называть производными или дочерними классами или классами – потомками. При этом, если базовый класс обладает фиксированным набором свойств и поведением, то производный от него должен содержать этот же набор свойств и подобное поведение, а так же дополнительные атрибуты, которые будут характеризовать уникальность и индивидуальность полученного класса. Тогда говорят, что производный класс наследует свойства и поведения базового или родительского класса.
Пример обозначений класса и связи между базовым и производным классом на языке UML. Стрелка указывает на базовый класс от производного.
Инкапсуляция
- Характеризует сокрытие отдельных деталей внутреннего устройства классов от внешних по отношению к нему объектов или пользователей. Инкапсуляция ведет свое происхождение от деления модулей, в некоторых языках программирования, на 2 части: интерфейс и реализацию. При этом в интерфейсной части модуля описываются все объявления, функций и процедур, а возможно и типов данных, доступных за пределами модуля. Указанные процедуры и функции являются способами оказания услуг внешним клиентам. В секции реализации содержится программный код, определяющий конкретные способы реализации объявленных в интерфейсной части процедур и функций. Объявление функции называется прототипом функции.
Полиморфизм
- понимается свойство объектов принимать различные внешние формы, в зависимости от обстоятельств. Применительно к ООП, полиморфизм означает, что действия, выполняемые одноименными методами, могут отличаться, в зависимости от того, к какому классу относится тот или иной метод.
Полиморфизм объектно-ориентированных языков связан с перегрузкой функции, но не тождественен ей. Важно понять, что имена методов и свойств тесно связаны с классами, в которых они описаны.
Полиморфизм тесно связан с механизмом работы виртуальных функции.
Double Sum (double a, double b)
{return a+b;}
Int Sum (int a, int b)
{return a+b;}
Double Sum (double* a, double b)
{double s=0.0;
For (int i=0; i<n; i++)
{s+=a[i]; return s;}
Double Sum (double a[10])
{double s=0.0;
For (int i=0; i<10; i++)
{s+=a[i];
return s;}
Нужная функция будет определена по значениям переменных.
Типы возвращаемого значения не относятся к типу функции.
Int main()
{ double* a=new double[10];
Sum (a,10);
Sum(a[10]);
Sum(10,10);
Sum(10.0,10.0);
}
Полиморфизм связан с механизмом перегрузки функции (приведенной выше) но не тождественен ей. Разница между перегрузкой функции и виртуальными функциями в том, что область видимости перегруженных функции глобальная. Они видны везде в программе, начиная с точки их объявления, а виртуальные функции видны только в том классе, в котором объявлены.
Определение собственных типов данных
Структура и класс.
Структура – собственный или пользовательский тип данных, определяемы с помощью ключевого слова “struct”.
Класс – тоже пользовательский или абстрактный тип данных, определяемый с помощью ключевого слова “class”.
Самое существенное отличие между структурой и классом заключаются в том, что все элементы структуры по умолчанию являются открытыми, то есть общедоступными, а элементы класса по умолчанию являются закрытыми или приватными. Элементы структуры, описываемые через данные, называют полями. Эти же элементы в классах называют данными членами. Элементы структуры, описываемые через функции, называют членами-функциями и функциями-членами.
Struct BOOK
{
Char title[80];
Char author[80];
Int year;
};
Class BOOK
{
Public:
Char title[80];
Char author[80];
Int year;
};
“public” является обязательным ключевым словом, если необходимо, чтобы члены класса были общедоступными.
Инициализация структуры
1 способ
BOOK Novel=
{“paneless programming”,
“I.C.Fingers,
};
В этом способе инициализации структуры инициализирующие значения появляются между фигурными скобками и разделены запятыми, при этом последовательность инициализирующих значений должна совпадать с последовательностью членов структуры ее определения.
Указатель – легальная переменная.
…
Пропустил
…
Таким образом, к членам структуры или класса можно обратиться через операцию прямого доступа (точка), используя либо сам объект, либо ссылку на него или через операцию косвенного (непрямого) доступа (стрелка), используя указатель на объект (то есть через его адрес). Таким же образом передачи переменных типа структуры или класса, как и обычные типы данных, в функцию производятся по имени (значению), по ссылке или через указатель на структуру или на класс.
{Struct Box
Double l,h,w;
Double volume () {return l*h*w;}
};
Box ShowIt(Box aBox)
{Box bBox;
bBox.l=2*aBox.l;
bBox.h=3*aBox.h;
bBox.w=4*aBox.w;
return bBox;
}
Int main()
{Box matchbox;
Matchbox.l=4.0;
Matchbox.h=2.5;
Matchbox.w=4.5;
Cout<<”The Volume of matchbox= “<<Matchbox.volume()<<endl;
Matchbox=showIt(matchbox);
Cout<<”l= “<<matchbox.l<<endl;
Cout<<”h= “<<matchbox.h<<endl;
Cout<<”w= “<<matchbox.w<<endl;
Cout<<”The new Volume of matchbox= “<<Matchbox.volume()<<endl;
Return 0;}
Замечание:
Передачу экземпляров из структуры или классов по значению можно осуществить только в том случае, если эти объекты не созданы динамической памятью с помощью операции “new”.
Box* ShowIt(Box* aBox)
{Box bBox=&aBox;
bBox->l=2*aBox->l;
bBox->h=3*aBox->h;
bBox->w=4*aBox->w;
return bBox;
}
Int main()
{Box matchbox=new Box;
Matchbox->l=4.0;
Matchbox->h=2.5;
Matchbox->w=4.5;
Cout<<”The Volume of matchbox= “<<Matchbox->volume()<<endl;
Matchbox=showIt(matchbox);
Cout<<”l= “<<matchbox->l<<endl;
Cout<<”h= “<<matchbox->h<<endl;
Cout<<”w= “<<matchbox->w<<endl;
Cout<<”The new Volume of matchbox= “<<Matchbox->volume()<<endl;
Return 0;}
Никогда!Не!Возвращать!Адрес!Локального!Объекта!
Ссылочный вариант:
struct Box
{
double l,h,w;
double volume () {return l*h*w;}
};
Box ShowIt(Box aBox)
{
Box bBox;
Box& rBox = bBox;
rBox.l=2*aBox.l;
rBox.h=3*aBox.h;
rBox.w=4*aBox.w;
return rBox;
}
int main()
{
Box matchbox;
Box& Rmatchbox=matchbox;
Rmatchbox.l=4.0;
Rmatchbox.h=2.5;
Rmatchbox.w=4.5;
cout<<"The Volume of matchbox= "<<Rmatchbox.volume()<<endl;
Rmatchbox=ShowIt(Rmatchbox);
cout<<"l= "<<Rmatchbox.l<<endl;
cout<<"h= "<<Rmatchbox.h<<endl;
cout<<"w= "<<Rmatchbox.w<<endl;
cout<<"The new Volume of matchbox= "<<Rmatchbox.volume()<<endl;
system ("pause");
return 0;
}
Все упомянутое про структуры можно использовать и в классах.
Функция член класса, это функция, определение или прототип которой находится внутри определенного класса. Она оперирует любым объектом класса, членом которого является и имеет доступ ко всем членам объекта этого класса. Определение функции члена должно быть помещено внутрь определенного класса. Однако, если мы хотим разместить его вне определения класса, то внутри класса потребуется указать прототип этой функции члена.
Для того, чтобы определить функцию вне класса, необходимо указать ее область видимости с помощью операции размещения контекста (::)
using std::cout;
using std::cin;
using std::endl;
class Box
{
public:
double l,h,w;
double volume ();
};
double Box::volume()
{return l*h*w;}
int main()
{
int value=0;
cout<<"enter the Value"<<endl;
cin>>value;
cout<<"your Value is "<<value<<endl;
system ("pause");
return 0;
}
В случае, когда функция определяется внутри определения класса, то компилятор неявно ее трактует как встроенную (inline) функцию.
Встроенная функция
…Многопропусков…
Присваивание параметрам в классе значений по умолчанию.
Class Bar
{
Public:
Box(){cout<<”default constructor called\n”;}
Box(double fr=1.0, double hv=1.0, double bv=1.0
{ cout<<”Constructor called\n”;
L=lv;H=hv;W=bv;}
double Volume() {return L*H*W;}
Double L,H,W;
};
Int main()
{
Box box1;
Box matchbox(1.5,2.5,2.0);
Double V=box1.volume();
Cout<<”the volume of box1=”<<V<<endl;
Cout<<”the volume of matchbox=”<< matchbox.volume()<<endl;
Return 0;
}
Если запустить такую программу, то мы получим сообщение об ошибке, а именно, компилятор считает, что определено множество конструкторов по умолчанию и он не может решить, какой из них следует вызывать для того, чтобы создать объект без параметров (Box1). Дело в том, что объект Box1 требует конструктор без параметров, а теперь оба конструктора могут быть вызваны без параметров. Решение подобной проблемы заключается в том, чтобы избавиться от конструктора без параметра. Закомментируем строчку под public и все заработает.
Class Box
{
Public:
Box(double fr=1.0, double hv=1.0, double bv=1.0
{ cout<<”Constructor called\n”;
L=lv;H=hv;W=bv;}
double Volume() {return L*H*W;}
Double L,H,W;
};
Int main()
{
Box matchbox(1.5,2.5,2.0);
Box box1(matchbox);
Double V=box1.volume();
Cout<<”the volume of box1=”<<V<<endl;
Cout<<”the volume of matchbox=”<< matchbox.volume()<<endl;
Return 0;
}
Допустим, мы хотим инициализировать объект box1 через matchbox. Это значит, что мы хотим создать объект box1 через matchbox. В таких случаях вызывается конструктор копирования по умолчанию. Конструктор копирования создает объект класса, инициализируя его объектом того же класса. В каких то случаях, компилятор генерирует версию конструктора копирования по умолчанию. Такой конструктор создает новый объект путем копирования существующего член за членом. Однако, этого достаточно для таких простых классов, как наш класс box, в которых не содержатся указатели или массивы, в качестве членов. В каких то случаях мы сами обязаны создать конструктор копирования.
Дружественные функции
Бывают случаи, когда по некоторым причинам необходимо, чтобы некоторые функции, не являющиеся членом класса, имели доступ к приватным членам функции. Такие функции называются дружественными функциями класса и определяются с помощью ключевого слова friend. В самом классе можно либо указать прототип дружественной функции, либо целиком ее определение. Так как дружественные функции не являются членами класса, то атрибуты доступа не относятся к ней. Это класс функций с некоторыми привилегиями (есть доступ ко всем членам класса), которыми не могут пользоваться обычные глобальные.
Примечание: в соответствии с используемым нами стилем программирования, дружественная функция должна быть описана в конце класса.
Пример:
Создадим дружественную функцию, которая будет возвращать сумму поверхностей ящика.
Class Box
{
Private:
double L,H,W;
Public:
Box(double fr=1.0, double hv=1.0, double bv=1.0
{ cout<<”Constructor called\n”;
L=lv;H=hv;W=bv;}
double Volume() {return L*H*W;}
Double Get_lenght();
Inline double Box::Get_length(){return L;}
Friend double BoxSurface(Box aBox);
};
Double BoxSurface(Box aBox);
Return 2*(aBox.L* aBox.H+ aBox.L* aBox.W+ aBox.H* aBox.W)
Int main()
{
Box matchbox(1.5,2.5,2.0);
Box box1(matchbox);
Double V=box1.volume();
Cout<<”the volume of box1=”<<V/box1.Get_lenght()<<endl;
Cout<<”the volume of matchbox=”<< matchbox.volume()<<endl;
Return 0;
}
Интересным применением указателя this является недопущения присваивания самому себе. В дальнейшем мы увидим, что присваивание объекта самому себе может вызвать серьезные ошибки, если объекты содержат указатели на выделенную динамическую память.
Статические члены класса
Double sum (double a, double b)
{ static int count=0;
Count++;
Cout<<”this function has been called ”<<count<<”times”<<endl;
return a+b;}
int main()
{
…
Sum(5.0,5.0);
…
Sum(5.0,5.0);
…
Return 0;
}
Статические члены класса
Статические данные-члены
Статические функции-члены
Статические данные-члены дают такой эффект, что они создаются в единственном экземпляре и разделяются всем объектами класса.
Обычные данные-члены создаются в виде копии для каждого объекта. Но для всего класса имеется только по одному экземпляру каждого статического члена независимо от того, сколько объектов этого класса было определено.
Static int count; - статическая переменная, по умолчанию имеет значение 0, существует во время выполнения всей программы. Локальные же имеют по умолчанию «мусорное» значение, существуют только в своем блоке программы.
Одним из практических применений статических переменных является подсчет количества вызовов функции.
Double sum (double a, double b)
{
static int count;
Count++;
Cout<<”sum was been called ”<<count<<” times”<<endl;
Return a+b;
}
Int main()
{
sum (5,3);
…
Sum(10,3);
…
Return 0;
}
Class Box
{
Public:
Static int count;
…
Private:
Double L,H,W;};
Одним из практичских применений статических переменных является подсчет существующих объектов класса. Для этого его нужно поместить в общедоступный раздел класса.
Как инициализировать данный объект класса?
Нельзя инициализировать в самом классе, т.к. класс общая модель для создания любого объекта класса. Мы не можем его инициализировать в конструкторе т.к. мы желаем его значения увеличивать при каждом вызове конструктора для создания объектов.
Мы не можем инициализировать его в другом функции-члене, т.к. она будет ассоциироваться с объектом, а инициализация этого статического члена нужна для любого объекта. Значит статический данный-член нужно инициализировать вне класса с помощь оператора int Box::count=0;
Class Box
{
Public:
Static int count;
Box( double pv, double hv=1.0, double bv=1.0)
{ cout <<”constructor called”;
L=H=W=1.0;
Count++;}
Couble Volume() {return L*H*W;}
Private:
Double L,H,W;
};
Int Box::count=0;
Int main()
{
Box boxes[5];
Box cigar (2.0, 5.0, 1.0);
Cout<<”\n\n Number of objects (through class)=”<<box.count<<endl;
Cout<<”\n\n Number of objects (through object)=”<<boxes[2].count<<endl;
Return 0;
}йомахарт ймасоул nhgjhygjuloilhgbg
Статические члены класса существуют, даже если никаких объектов не было создано и это очевидно из того, что они инициализируются до того, как объявлен любой объект класса. Статические данные члены создаются автоматически при запуске программы и инициализируются нулем, если только мы не инициализируем их другим значением.
Статические функции-члены класса.
Объявляя функцию-член класса как статическую, мы делаем ее независимой от любого конкретного объекта класса. Обращения членам класса из статической функции члена должно выполняться с использованием квалифицированных имен.
Статическая функция-член обладает таким преимуществом, что она существует и может быть вызвана даже тогда, когда еще не существует ни одного объекта данного класса. В этом случае в ней могут использоваться только статические данные члены класса, поскольку на этот момент только они и существуют.
Таким образом, статическая функция-член может быть вызвана для проверки статических данных-членов, даже если мы не знаем, существуют ли объекты этого класса и если они существуют, то сколько. Статическая функция-член может обращаться как к приватным, так и к общедоступным членам класса.
Static int Function(int N);
aBox.Function(5);
Box::Function(5);
Массив объекта
Массив может хранить объекты любого типа, как встроенного, так и собственного пользовательского типа. При объявлении массива компилятору сообщают количество хранимых объектов (размер массива), что позволит выделить участок памяти требуемого размера и тип объекта. Для того, чтобы объекты могли быть созданы при определении массива, класс должен обладать конструктором по умолчанию без параметров. Для обращения к членам массива сначала используется операция индексации ([..]), а затем, с помощью операции прямого доступа, получают доступ к определенному члену класса. Количество выделенной памяти для всего массива, компьютер выделяет на основании типа.
Int main()
{
Box boxes[5];
Box cigar(8.0,5.0,1.0);
Boxes[3]=cigar;
Cout<<”the volume of boxes[1]= “<<boxes[1].Volume()<<endl;
Cout<<”the volume of boxes[4]= “<<boxes[4].Volume()<<” =”Volume of cigar= “<<cigar.Volume()<<endl;
Return 0;
}
Деструкторы
Деструктор – функция, которая уничтожает объект, когда необходимость в нем отпадает или когда он выходит из области видимости. Разрушение объектов включает освобождение памяти, занятой данными членами объекта, за исключением статических членов, которые продолжают существовать. Даже когда не остается ни одного экземпляра класса. Деструктор – особая функция, имя которой совпадает с именем класса, но предваренное символом ~(тильда). Деструктор не возвращает значения (не имеет типа возврата) и не принимает параметров, следовательно его невозможно перегружать и он может быть в классе только один.
Class Box
{public:
~Box(){cout<<”destructor called/n”;}
Box(double lv=1.0, double hv=1.0, double bv=1.0)
{L=lv;H=hv;W=bv;
Cout<<”constructor called\n”;}
Double Volume(){return L*H*W;}
Private:
Double L,H,W;
};
Int main()
{ Box boxes[5]
Box cigar(8.0,5.0,1.0);
Box match(2.2,1.1,0,5);
Box* PB1=&cigar;
Box* PB2=Null;
Cout<<endl<<”the cigar Volume= ”<<PB1->Volume()<<endl;
PB2=boxes;
Boxes[2]=match;
Cout<<”the volume of boxes[2]= “<<(PB+2)->Volume()<<endl;
Return0;
}
Замечание:
При присваивании указателю PB2 массива boxes, происходит передача адреса первого элемента массива boxes.
При вызове Volume(), для выбора необходимого нам 3-го элемента массива, мы можем просто прибавить к нашей позиции(1-й элемент) еще 2 позиции и получим 3-й элемент.
Перегрузка операции
Методология ООП
Модель – абстракция физической системы, просматриваемая с определенной точки зрения и представленная на некотором языке или в графическом виде. С точки зрения принципов системного анализа, одна и та же физическая система может быть представлена разными моделями. А назначение каждой модели для одной и той же системы определяется характером решаемой задачи изучаемой проблемы.
Основное требование к модели программы – она должна быть понятна заказчику программы, пользователю и группе программистов – разработчиков.
Объектно-ориентированное программирование – совокупность технологий, принципов, инструментальных средств, для создания программных систем на основе архитектуры взаимодействия объектов.
Основные принципы ООП:
1) Абстракция
2) Инкапсуляция
3) Наследование
4) Полиморфизм (многообразие)
Пример описания модели:
Class Box
{
Public:
Double H;
Double L;
Double W;
Double volume ()
{return H*L*W;}
};
Абстракция
– характеристика сущности, которая отличает ее от других сущностей. Абстракция определяет границу представления соответствующего объекта модели и применяется для определения таких фундаментальных понятий ООП как класс или объект.
Принцип абстракции гласит, что чем больше атрибутов и операций принимается во внимание, то тем ближе полученная модель будет описывать реальную систему.
Класс представляет собой абстракцию совокупности реальных объектов, которые имеют общий набор свойств и обладают одинаковым поведением.
Объект (в контексте ООП) рассматривается как экземпляр соответствующего класса.
Объекты, которые не имеют идентичных свойств или не обладают одинаковым поведением, по определению не могут быть отнесены к одному классу.
Классы можно организовать в виде иерархической структуры, которая напоминает схему классификации понятий в понятийной логике. В качестве более общего понятия или категории берется понятие, имеющее наибольший объем и наименьшее содержание. Это – самый высокий уровень абстракции для данной иерархии. Затем данное общее понятие конкретизируется, то есть уменьшается его объем и увеличивается его содержание. Появляется менее общее понятие, которое на схеме иерархии будет расположено на уровень ниже исходного. Этот процесс конкретизации понятий может быть продолжен до тех пор, пока на самом нижнем уровне не будет получено понятие, дальнейшая конкретизация которого либо невозможна, либо нецелесообразна.
Принцип, в соответствии с которым знание о наиболее общей категории разрешается применять для более частной категории, называется наследованием. Наследование тесно связано с иерархией классов, определяющей, какие классы следует считать наиболее абстрактными и общими по отношению к другим классам. Наиболее общий или абстрактный класс, будем называть базовым или родительским классом, или классом – предком. А частный случай от родительского класса будем называть производными или дочерними классами или классами – потомками. При этом, если базовый класс обладает фиксированным набором свойств и поведением, то производный от него должен содержать этот же набор свойств и подобное поведение, а так же дополнительные атрибуты, которые будут характеризовать уникальность и индивидуальность полученного класса. Тогда говорят, что производный класс наследует свойства и поведения базового или родительского класса.
Пример обозначений класса и связи между базовым и производным классом на языке UML. Стрелка указывает на базовый класс от производного.
Инкапсуляция
- Характеризует сокрытие отдельных деталей внутреннего устройства классов от внешних по отношению к нему объектов или пользователей. Инкапсуляция ведет свое происхождение от деления модулей, в некоторых языках программирования, на 2 части: интерфейс и реализацию. При этом в интерфейсной части модуля описываются все объявления, функций и процедур, а возможно и типов данных, доступных за пределами модуля. Указанные процедуры и функции являются способами оказания услуг внешним клиентам. В секции реализации содержится программный код, определяющий конкретные способы реализации объявленных в интерфейсной части процедур и функций. Объявление функции называется прототипом функции.
Полиморфизм
- понимается свойство объектов принимать различные внешние формы, в зависимости от обстоятельств. Применительно к ООП, полиморфизм означает, что действия, выполняемые одноименными методами, могут отличаться, в зависимости от того, к какому классу относится тот или иной метод.
Полиморфизм объектно-ориентированных языков связан с перегрузкой функции, но не тождественен ей. Важно понять, что имена методов и свойств тесно связаны с классами, в которых они описаны.
Полиморфизм тесно связан с механизмом работы виртуальных функции.
Double Sum (double a, double b)
{return a+b;}
Int Sum (int a, int b)
{return a+b;}
Double Sum (double* a, double b)
{double s=0.0;
For (int i=0; i<n; i++)
{s+=a[i]; return s;}
Double Sum (double a[10])
{double s=0.0;
For (int i=0; i<10; i++)
{s+=a[i];
return s;}
Нужная функция будет определена по значениям переменных.
Типы возвращаемого значения не относятся к типу функции.
Int main()
{ double* a=new double[10];
Sum (a,10);
Sum(a[10]);
Sum(10,10);
Sum(10.0,10.0);
}
Полиморфизм связан с механизмом перегрузки функции (приведенной выше) но не тождественен ей. Разница между перегрузкой функции и виртуальными функциями в том, что область видимости перегруженных функции глобальная. Они видны везде в программе, начиная с точки их объявления, а виртуальные функции видны только в том классе, в котором объявлены.
Определение собственных типов данных
Структура и класс.
Структура – собственный или пользовательский тип данных, определяемы с помощью ключевого слова “struct”.
Класс – тоже пользовательский или абстрактный тип данных, определяемый с помощью ключевого слова “class”.
Самое существенное отличие между структурой и классом заключаются в том, что все элементы структуры по умолчанию являются открытыми, то есть общедоступными, а элементы класса по умолчанию являются закрытыми или приватными. Элементы структуры, описываемые через данные, называют полями. Эти же элементы в классах называют данными членами. Элементы структуры, описываемые через функции, называют членами-функциями и функциями-членами.
Struct BOOK
{
Char title[80];
Char author[80];
Int year;
};
Class BOOK
{
Public:
Char title[80];
Char author[80];
Int year;
};
“public” является обязательным ключевым словом, если необходимо, чтобы члены класса были общедоступными.
Инициализация структуры
1 способ
BOOK Novel=
{“paneless programming”,
“I.C.Fingers,
};
В этом способе инициализации структуры инициализирующие значения появляются между фигурными скобками и разделены запятыми, при этом последовательность инициализирующих значений должна совпадать с последовательностью членов структуры ее определения.
Указатель – легальная переменная.
…
Пропустил
…
Таким образом, к членам структуры или класса можно обратиться через операцию прямого доступа (точка), используя либо сам объект, либо ссылку на него или через операцию косвенного (непрямого) доступа (стрелка), используя указатель на объект (то есть через его адрес). Таким же образом передачи переменных типа структуры или класса, как и обычные типы данных, в функцию производятся по имени (значению), по ссылке или через указатель на структуру или на класс.
{Struct Box
Double l,h,w;
Double volume () {return l*h*w;}
};
Box ShowIt(Box aBox)
{Box bBox;
bBox.l=2*aBox.l;
bBox.h=3*aBox.h;
bBox.w=4*aBox.w;
return bBox;
}
Int main()
{Box matchbox;
Matchbox.l=4.0;
Matchbox.h=2.5;
Matchbox.w=4.5;
Cout<<”The Volume of matchbox= “<<Matchbox.volume()<<endl;
Matchbox=showIt(matchbox);
Cout<<”l= “<<matchbox.l<<endl;
Cout<<”h= “<<matchbox.h<<endl;
Cout<<”w= “<<matchbox.w<<endl;
Cout<<”The new Volume of matchbox= “<<Matchbox.volume()<<endl;
Return 0;}
Замечание:
Передачу экземпляров из структуры или классов по значению можно осуществить только в том случае, если эти объекты не созданы динамической памятью с помощью операции “new”.
Box* ShowIt(Box* aBox)
{Box bBox=&aBox;
bBox->l=2*aBox->l;
bBox->h=3*aBox->h;
bBox->w=4*aBox->w;
return bBox;
}
Int main()
{Box matchbox=new Box;
Matchbox->l=4.0;
Matchbox->h=2.5;
Matchbox->w=4.5;
Cout<<”The Volume of matchbox= “<<Matchbox->volume()<<endl;
Matchbox=showIt(matchbox);
Cout<<”l= “<<matchbox->l<<endl;
Cout<<”h= “<<matchbox->h<<endl;
Cout<<”w= “<<matchbox->w<<endl;
Cout<<”The new Volume of matchbox= “<<Matchbox->volume()<<endl;
Return 0;}
Никогда!Не!Возвращать!Адрес!Локального!Объекта!
Ссылочный вариант:
struct Box
{
double l,h,w;
double volume () {return l*h*w;}
};
Box ShowIt(Box aBox)
{
Box bBox;
Box& rBox = bBox;
rBox.l=2*aBox.l;
rBox.h=3*aBox.h;
rBox.w=4*aBox.w;
return rBox;
}
int main()
{
Box matchbox;
Box& Rmatchbox=matchbox;
Rmatchbox.l=4.0;
Rmatchbox.h=2.5;
Rmatchbox.w=4.5;
cout<<"The Volume of matchbox= "<<Rmatchbox.volume()<<endl;
Rmatchbox=ShowIt(Rmatchbox);
cout<<"l= "<<Rmatchbox.l<<endl;
cout<<"h= "<<Rmatchbox.h<<endl;
cout<<"w= "<<Rmatchbox.w<<endl;
cout<<"The new Volume of matchbox= "<<Rmatchbox.volume()<<endl;
system ("pause");
return 0;
}
Все упомянутое про структуры можно использовать и в классах.
Функция член класса, это функция, определение или прототип которой находится внутри определенного класса. Она оперирует любым объектом класса, членом которого является и имеет доступ ко всем членам объекта этого класса. Определение функции члена должно быть помещено внутрь определенного класса. Однако, если мы хотим разместить его вне определения класса, то внутри класса потребуется указать прототип этой функции члена.
Для того, чтобы определить функцию вне класса, необходимо указать ее область видимости с помощью операции размещения контекста (::)
using std::cout;
using std::cin;
using std::endl;
class Box
{
public:
double l,h,w;
double volume ();
};
double Box::volume()
{return l*h*w;}
int main()
{
int value=0;
cout<<"enter the Value"<<endl;
cin>>value;
cout<<"your Value is "<<value<<endl;
system ("pause");
return 0;
}
В случае, когда функция определяется внутри определения класса, то компилятор неявно ее трактует как встроенную (inline) функцию.
Встроенная функция
…Многопропусков…
Присваивание параметрам в классе значений по умолчанию.
Class Bar
{
Public:
Box(){cout<<”default constructor called\n”;}
Box(double fr=1.0, double hv=1.0, double bv=1.0
{ cout<<”Constructor called\n”;
L=lv;H=hv;W=bv;}
double Volume() {return L*H*W;}
Double L,H,W;
};
Int main()
{
Box box1;
Box matchbox(1.5,2.5,2.0);
Double V=box1.volume();
Cout<<”the volume of box1=”<<V<<endl;
Cout<<”the volume of matchbox=”<< matchbox.volume()<<endl;
Return 0;
}
Если запустить такую программу, то мы получим сообщение об ошибке, а именно, компилятор считает, что определено множество конструкторов по умолчанию и он не может решить, какой из них следует вызывать для того, чтобы создать объект без параметров (Box1). Дело в том, что объект Box1 требует конструктор без параметров, а теперь оба конструктора могут быть вызваны без параметров. Решение подобной проблемы заключается в том, чтобы избавиться от конструктора без параметра. Закомментируем строчку под public и все заработает.
Class Box
{
Public:
Box(double fr=1.0, double hv=1.0, double bv=1.0
{ cout<<”Constructor called\n”;
L=lv;H=hv;W=bv;}
double Volume() {return L*H*W;}
Double L,H,W;
};
Int main()
{
Box matchbox(1.5,2.5,2.0);
Box box1(matchbox);
Double V=box1.volume();
Cout<<”the volume of box1=”<<V<<endl;
Cout<<”the volume of matchbox=”<< matchbox.volume()<<endl;
Return 0;
}
Допустим, мы хотим инициализировать объект box1 через matchbox. Это значит, что мы хотим создать объект box1 через matchbox. В таких случаях вызывается конструктор копирования по умолчанию. Конструктор копирования создает объект класса, инициализируя его объектом того же класса. В каких то случаях, компилятор генерирует версию конструктора копирования по умолчанию. Такой конструктор создает новый объект путем копирования существующего член за членом. Однако, этого достаточно для таких простых классов, как наш класс box, в которых не содержатся указатели или массивы, в качестве членов. В каких то случаях мы сами обязаны создать конструктор копирования.
Приватные или защитные члены класса
Для защиты членов класса используется ключевое слово private. Члены класса, специфицированные или объявленные, как приватные, в общем случае могут быть доступны только функциям-членам этого же класса.
Class Box
{
Private:
double L,H,W;
Public:
Box(double fr=1.0, double hv=1.0, double bv=1.0
{ cout<<”Constructor called\n”;
L=lv;H=hv;W=bv;}
double Volume() {return L*H*W;}
};
Int main()
{
Box matchbox(1.5,2.5,2.0);
Box box1(matchbox);
Double V=box1.volume();
Cout<<”the volume of box1=”<<V<<endl;
Cout<<”the volume of matchbox=”<< matchbox.volume()<<endl;
Return 0;
}
Наличие возможности спецификации членов класса как приватные, позволяет отделить интерфейс класса от его внутренней реализации, где интерфейс класса состоит из общедоступных (public) функций членов, поскольку они могут обеспечить непрямой доступ ко всем членам класса, включая приватные. Сохраняя внутренности класса приватными, позднее их можно модифицировать без необходимости модификации остального кода, который используется этим классом через его общедоступный интерфейс.