Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AllCandC++Lectures.docx
Скачиваний:
2
Добавлен:
25.09.2019
Размер:
52.56 Кб
Скачать

Неявный указатель this

При создании нового объекта класса выделяется память для всех его нестатических полей. То есть каждый экземпляр объекта имеет свой набор полей. Методы класса существуют в единственном экземпляре для всех его объектов. При вызове методов класса нам не нужно среди аргументов указывать объект класса, для которого вызывается метод. Возникает вопрос, как метод узнает, какой объект его вызвал. Это обеспечивает компилятор, который для каждого метода предусматривает дополнительный аргумент - указатель на объект, вызвавший метод. При вызове метода добавляется соответствующий фактический параметр. Программист может не знать об этом. Поэтому этот аргумент называют неявным указателем и обозначают this. This можно использовать и явно, в тех местах, где необходим указатель на текущий объект. Пример:

Рассмотрим класс списков: class list, функция insert(list *pElem); позволяет вставить новый элемент вслед за текущим. pElem->next=next;

pElem->prev=this;

next->prev=pElem;

Thi->next=pElem;

Пример 2:

Class test {

Int a,b;

Public:

Test(int A, int B) {a=A; b=B};

Test& printA() {cout<<a; return *this;}

Test& printfB() {cout<<b; return *this;}

Main() {

Test x(5,6);

X.printA().printB();

(X.printA()).printB();

*This - это сам объект, а так как функция возвращает ссылку, то x.printA() вернет сам объект x.

Статические методы классов

Статические методы отличаются от нестатических тем, что им не передается указатель this. То есть эти методы не привязаны к конкретному объекту и являются методами класса. Поэтому к ним можно обращаться еще до того как был создан 1й объект класса. В классе можно переопределить операцию new. Для того чтобы сделать метод статическим, нужно в описании класса добавить к его определению static. Можно делать так: x.print(); или, не создавая объекта, обратиться напрямую к функции: test::print();.

Конструктор копирования

Class test {

Int I;

Public:

Test() { cout<<"default"<<endl;

I=1; }

Int getI() { return i;}

Void setI(int i0) {i=i0; }

};

Void main() {test a, b=a;

B.setI(b.getI()+1);

Cout<<b.getI();

}

В этой программе конструктор без параметров будет вызван 1 раз, для создания объекта a. Последняя печать показывает, что у объекта b поле I хранит значение 2. Можно убедиться, что у объекта a оно равно 1. Для создания любого объекта должен быть вызван конструктор. Так как b и a хранят разные значения поля i, то это два разных объекта. А конструктор для b не вызывался. Это возможно, потому что компилятор помимо конструктора без параметров создает еще 1 тип конструктора для инициализации объектов другими объектами того же класса. В данном случае объект b инициализируется объектом a того же класса test. Этот конструктор называется конструктором копирования. В простых случаях компилятор выполняет копирование каждого поля из одного объекта в другой. При инициализации объекта b объектом a копируется поле i со значением единицы.

В тех случаях, когда программиста не устраивают действия конструктора копирования по умолчанию, можно написать свой вариант.

Test( const test& t)

Особенность конструктора копирования в том, что его первый аргумент всегда ссылка на объект своего класса. Можно запретить изменять объект при помощи const. При необходимости у конструктора копирования могут быть еще и другие параметры. Конструктор копирования вызывается:

1) при явной инициализации с помощью объекта данного класса: test a, a=b;

2) при вызове функции, у которой аргумент имеет тип данного класса: void f(test t) {}; f(b); t будет инициализироваться b.

3) Когда функция возвращается объект данного класса:

test f(test t( {

Return t;}

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

Пример необходимости создания своего конструктора копирования:

Class string1 {

Unsigned size;

Char *p;

Public:

String1(char s[]) {

P=new char[size=strle(S)+1];

Strcpy(p, S); }

~string1(){delete [ ] p;}

};

Void main() {

...

String1 s1("str");

{

String1 s2=s1;

} // переменная s2 будет существовать, пока мы не достигнем этой скобки. При выходе из блока, отработает деструктор, который освободит память, занятую строкой. Объект s1 будет также существовать.

...

}

Рассмотрим подробнее s2=s1; Будет вызван конструктор копирования по умолчанию. В результате s2.p будет хранить тот же адрес, что и s1.p. Когда отрабатывает деструктор для s2, освобождается память, которая еще используется s1. Чтобы не было этой ошибки нужно в программу добавить конструктор копирования, который будет выделять память для новой копии строки помещать туда эту строку:

String1( string1&S) {

P=new char[s.size+1];

Strcpy(p, s.p);

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]