
- •Int main()
- •Int main()
- •Int main()
- •Int main()
- •Int main()
- •Int main()
- •Int main()
- •Int main ()
- •Int main()
- •Int main()
- •Int main()
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
- •Int main(){
Операции new/delete.
Переопределение операций.
A *pa;
pa=new A; -> obj.operator new (size_t unsigned size)
Задачей new не является вызов конструктора, он вызывается потом.
…
delete pa;
…
}
new и delete перегружаются парой. Если перегрузить new, нужно перегрузить delete.
new[]/delete[] для массивов
new[] так же получает один явный аргумент – размер всего создаваемого массива объектов.
#include <cstdlib>
using namespace std;
/*все имена стандартной библиотеки находятся в std*/
/*За счет этого имеет прямой доступ ко всем именам стандартной библиотеки C++*/
class A
{
public:
void *operator new(size_t size)
return malloc(size);
}
void operator delete (void *p)
{
free(p);
void *operator new[] (size_t size)
{
return malloc(size);
}
void delete[] (void *p)
{
free(p);
}
};
int main()
{
A *pa;
pa=new A;
delete pa;
pa=new A[10];
delete [] pa;
return 0;
}
Конструкторы преобразования и операции привидения типа.
Конструктор преобразования – конструктор с одним аргументом.
Он позволяет преобразовать объект чужого типа в объект нашего класса. Тип аргумента конструктора и является преобразуемым чужим типом.
int i=10;
A(i)
void f(A x);
int main()
{
f(10);
…
}
class A
{
int a;
public:
explicit A(int x=0)
{
(*) a=x;
}
int get A() {return a;}
void set A(int x) {a=x;}
};
void f (double);
f (1);
A b (10); //нет преобразования
Сейчас конструктор А может использоваться в 2-х случаях:
как обычный конструктор, вызываемый для инициализации вновь созданного объекта.
как конструктор преобразования целого значения в объект класса А.
explicit используется для конструкторов преобразования, но запрещает использовать конструктор, как конструктор преобразования (кроме С++11).
Операция привидения типа.
А а(10);
int i;
i=(int)a; -> a.operator int() &a this /*выполнить такую операцию привидения типа можно только, если в классе А разрешено привидение типа к int (целому)*/
i=(int) 1.73;
(*)
operator int
return a;
}
Для операции привидения типа не указывается тип возвращаемого значения, но эта операция обязана вернуть значения (в теле должен быть return).
Пример: класс представляющий двусвязный список.
Возможными понятиями являются:
узел списка
struct ListNode
{
int key;
char *data;
ListNode *prev;
*next;
};
список
class List
{
struct ListNode
{
int key;
char *data;
ListNode *prev;
*next;
};
ListNode *first;
public:
List() {first=0;}
~List() {delist ();}
void add (int key, char *data);
…
};
Обычно пользователю класса List не нужно знать о существовании ListNode, тогда можно спрятать ListNode в класс List (важно в какую секцию).
Константные поля и константные объекты класса.
class A
{
int a;
const int b;
public:
A(int _a=0, int _b=0) : b(_b), a(_a)
{
//a=_a;
(x) b=_b; /*по синтаксису С++ это попытка изменить значение константы*/
/*Константные поля получают свои значения в списке инициализации конструктора.
Список инициализации можно задавать только для конструкторов класса*/
};
/*Ссылки в С++ ведут себя как константы*/
int x=5;
int &ri=x;
/*Если полем класса является ссылка, то она инициализируется в списке инициализации конструкторов*/
A a1(-1, 2025), a2(10), //b=2025, b=10
a3; //b=10
Есть такие поля и методы, которые принадлежат классу в целом.
Константные объекты.
const A a;
Объект любого класса можно создать, как константный.
class A
{
int a;
mutable int b;
public:
A(int _a=0, int b=0) : ()b(_b), a(_a)
{ }
int get A() {return 0;}
void set A(int x) {a=x;}
int get B() const
{return b;}
void set A(int x) const
{b=x;}
};
Int main()
{
const A a;
(x) x=a.get B(); // разрешено
(x) a.set B(125); // разрешено
(x) a.set A(-1);
…
};
Для константных объектов разрешен вызов только константных методов.
Константный метод в общем случае не может изменять значение полей класса.
Чтобы метод был константным, нужно после списка его аргументов задать ключевое слово const.
mutable – модификатор, задаваемый при изменении полей класса. Такие поля могут изменяться в константных методах.
Поля и методы класса в целом.
Int main()
{
A a1, a2;
Обычно
поля, похожие на a и b
в примере существуют только для
каких-нибудь объектов класса.
Каждый объект обладает собственными копиями всех полей класса. Поэтому такие поля называют полями объектов класса.
a1.set A(-20);
a2.set A(20);
Обычные методы класса, подобные getA и setA не могут вызываться сами по себе, как внешние функции, а вызываются только для объектов класса. Их называют методами объектов класса.
Можно создавать такие поля и методы, которые не будут привязаны к конкретным объектам класса. Их называют полями и методами класса в целом. Такие поля и методы объявляются с помощью модификатора static.
class A
{
int a; // обычное поле класса
static int sa; /* поле класса в целом существует в единственном экземпляре, независимо от того, сколько объектов класса создано (даже если их нет). Статические поля хранятся в сегменте данных вместе с глобальными и статическими переменными*/
public: static int sa;
A(int x=0) : a(x) {}
void test()
{
cout<<”a=”<<a<<\’t’<<”sa=”<<sa<<endl;
};
/*Пока задано только описание поля sa, память для нее не выделена*/
int A:: sa; // int A:: sa=1;
Int main()
cout<<A:: sa<<endl;
A:: sa=-100;
A a1;
(x) a1.a=-1;
По умолчанию статические поля обнуляются.
class B
{
static cons tint b=10;
…
};
Старый стандарт разрешал такую конструкцию, так как для них память не выделяется.
Статические методы не привязаны к объектам класса. Их можно вызывать, даже когда нет объектов класса.
Пример:
class A
{
int a;
static int sa;
public:
A(int x=0) : a(x) {}
int getA() {return a;}
void setA (int x) {a=x;}
static int getSA() {return sa;}
static void setSA (int x)
{
sa=x;
??? a=x+1;
};
int A::sa=1;
Int main()
{
int i=A::getSA();
Статическим методам не передается скрытый аргумент this и это позволяет вызывать их при отсутствии экземпляров класса.
Статические методы можно вызывать, указывая объект класса, но this все равно передаваться не будет.
class A
{
int a;
A(int x=0) : a(x) {}
~A(){} A(A&x) {}
public:
int getA() {return a;}
void setA (int x) {a=x;}
};
Int main()
{
A a1, a2(-100); // нельзя
При создании объекта должен быть вызван конструктор. В примере создания объектов происходит вне классов, в чужой функции main. Для нее запрещен вызов конструктора класса (вызов закрытых объектов).
Конструкторы делают закрытыми, чтобы запретить создание объектов класса.
singleton – одиночка (один класс).
Если конструкторы закрытые, для создания объектов нужно использовать либо открытый метод класса, либо внешнюю функцию, если в ней есть доступ к закрытому методу класса (в С++ дружественная функция). Такие методы или функции называют фабрикой объектов класса.
static: A create (int x=0)
{
return *new A(x);
}
Фабрика должна быть реализована как статический метод, она вызывается, когда нет объектов класса.
A a1=A:: create (100); //вызов конструктора копирования
Нужно закрыть конструктор копирования.
A *pa;
pa=A::create(100);
pa->setA(-100);
…
}
static destroy (A *p)
{
delete p;
}
A::destroy (pa);
То же самое можно сделать для ссылки.
Общая структура программы на С++.
#include <iostream>
using namespace std;