Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

В состав любого объекта класса входят только данные-элементы этого класса, но не входят функции-элементы этого же класса.

10. Размещение объекта в глобальной области, в стеке или в динамической памяти.

Oбъявление класса – это всего лишь описание схемы будущего использования памяти, т.е. при объявлении класса не выделяется память ни в области кода, ни в области глобальных переменных, ни в области стека, ни в динамической памяти.

Для привязки объявленного класса к памяти необходимо создать экземпляр класса в памяти, который называется объектом данного класса. Каждый класс может иметь сколь угодно много точек привязки к памяти как на внешнем, так и на внутреннем уровнях. Другими словами, каждому классу может соответствовать несколько объектов, которые будут отличаться друг от друга местом расположения в памяти.

В состав любого объекта класса входят только данные-элементы этого класса, но не входят функции-элементы этого же класса.

Если объекты класса определены на внешнем уровне, то они располагаются в области глобальных переменных.

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

19. Объявление и определение дружественной функции класса.

Доступ к открытым данным-элементам класса типа public имеет любая функция не принадлежащая классу. При этом обращение к открытом данному-элементу класса в режимах записи/чтения осуществляется или по имени объекта, или по указателю на объект, или по ссылке на объект. Например:

ob.c = 25 или obPtr->c=25; или obRef->c=25;,

где ob – имя объявленного объекта, а с – переменная типа public из ob.

Доступ к закрытым данным-элементам класса типа private имеет или функции класса, или дружественные функции данному классу.

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

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

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

Чтобы объявить функцию другом класса, необходимо перед ее прототипом в описании класса поставить ключевое слово friend. Объявление дружественности (friend) не имеет отношение к спецификаторам доступа public и private к элементам класса. поэтому объявление дружественной функции может быть выполнено в любом месте описания класса.

Следующий пример иллюстрирует применение дружественных функций.

//PROG.4.1.CPP – имя файла #include<iostream> using namespace std;//множество зарезервированных имен, отличных от стандартных занятых языком class myclass{ public: myclass(int i, int j){n=i; d=j;} private: int n,d; //Объявление дружественных функций, в которые объект класса передается через параметры по значению friend int div(myclass ob); } //Определение дружественной функции класса int div(myclass ob) { if(!(ob.n%ob.d)) reurn 1; else return 0; } int main() { setlocale(LC_ALL, “.1251”) myclass ob1(10,2), ob2(13,3); if(div(ob1)) cout << “10 без остатка делится на 2”<<endl; else cout << “10 без остатка не делится на 2”<<endl; if(div(ob2)) cout << “13 без остатка делится на 3”<<endl; else cout << “13 без остатка не делится на 3”<<endl; return 0; }

 

//PROG.4.2.CPP – имя файла #include<iostream> using namespace std; class Count{ //Объявление дружественной функции, в которой через ссылочный параметр передается адрес загрузки объекта класса friend void setX(Count&, int); public: Count (){x=0;}//конструктор класса с умолчанием void print()const{cout<<x<<endl;} private: int x; } void setX(Count &c, int val) { c.x=val; } int main() { setlocale(LC_ALL, “.1251”) Count ob; cout << “ob.x после своего создания: ”; ob.print(); cout << “ob.x после вызова дружественной функции setX: ”; setX(ob, 8); ob.print(); return 0; }

Из приведенных примеров следует, что при определении дружественных функций, во-первых, не указывается принадлежность классу, и во-вторых, не используется ключевое слово friend.

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

28. Что является значением “указателя” и ”ссылки” на объект? Чем “ указатель” отличается от “ссылки” на объект?

Значением «указателя» является адрес начала загрузки в памяти объектов, а значением «ссылки» является адрес загрузки объектов в области стека оперативной памяти.

Ссылки на объекты являются ничем иным как указателями. Но при этом ссылки обладают следующими свойствами, которые отличают их от указателей:

1. Ссылки являются константными указателями, т.е. значение адресов, которые однажды занесены в ссылки, не могут быть изменены в течение программы. Следовательно, ссылки являются константными переменными.

2. Константность ссылок обуславливает обязательную инициализацию на этапе их объявления. В PROG1.CPP обязательная инициализация ссылок осуществляется оператором newtype& ob5Ref = ob5,&ob6Ref = ob6Ref;. Альтернативным способом объявления ссылок ob5Ref и ob6Ref является:

newtype &ob5Ref = ob5;

newtype &ob6Ref = ob6;.

Таким образом, из-за констанстности ссылок недопустимым является следующий оператор объявления ссылок:

newtype &ob5Ref, &ob6Ref;

3. Ссылки являются неявно разыменуемыми указателями, т.е. в ссылках, в отличие от указателей, не используется операция разыменования или разадресации (*), т.к. разыменование осуществляется автоматически.

Использование ссылок позволяет имитировать режим прямой адресации к объектам по аналогии с логическими адресами объектов ob5 и ob6. Например, в операторах

ob5.set_a(50);

ob6.set_a(60);

вызов функции set_a выполняется в режиме прямой адресации объектов ob5 и ob6 с использованием операции доступа (.). Аналогичными по внешнему виду являются операторы

ob5Ref.set_a(50);

ob6Ref.set_a(60);,

которые осуществляют вызов функции set_a как бы в режиме прямой адресации, но не объектов, а ссылок ob5Ref и ob6Ref на эти объекты, хотя на самом деле имеет место косвенная адресация объектов. Эффект псевдопрямой адресации определяет толкование ссылки, например ob5Ref, как логического синонима исходного имени объекта ob5.

Как и прежде конструктор с умолчанием автоматически вызывается после объявления каждого из объектов ob5 и ob6, но при этом после имени каждого объекта в круглых скобках указано значение, которое в качестве аргумента передается конструктору для инициализации закрытой переменной, а в соответствующем объекте. Например, оператор newtype ob5(1), ob6(2); объявляет объект ob5 и обуславливает вызов конструктора newtype, который инициализирует переменную а из ob5 с значением 1. Аналогичные действия осуществляются и для ob6, т.е. переменная а инициализируется с значением 2.

37. Явное и неявное использование указателя this в функциях класса. Организация сцепления вызовов функций класса.

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

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

Каждая функция-элемент класса обладает единственный указателем с предопределенным именем this, через который косвенно адресуются данные-элементы объекта, по отношению к которому вызывается функция класса. Иначе говоря, this содержит адрес загрузки объявленного объекта, для обработки переменных которого вызывается соответствующая функция класса.

Пусть ob и f() соответственно объект и функция некоторого класса. Тогда оператор вызова f() имеет вид: ob. f();. Выполнение этого оператора осуществляется в два этапа. В начале в указатель this функции f() записывается адрес загрузки в памяти объекта ob, затем осуществляется вызов f(). Поскольку указатель this у каждой функции класса единственный, то через this любая функция имеет доступ к переменным только одного объекта, который обусловил вызов этой функции, например с помощью оператора ob.f();.

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

Для переменных и функций класса инкапсуляция проявляется в следующем:

1) При обращении к переменной класса необходимо указывать адрес загрузки объекта, которому принадлежит переменная, при этом существует три варианта указания адреса загрузки – через использование имени объекта или указателя на объект, или ссылки на адрес загрузки объекта.

2) При обращении к функциям класса необходимо указывать адрес загрузки объекта, по отношению к которому вызывается функция класса.

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

Функция класса находится в области действия class тогда и только тогда, когда она вызывается внутри другой функции этого же класса по отношению к объекту, адрес загрузки которого, располагается в указатели this вызывающей функции класса.

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

Две следующие программы иллюстрируют явное и неявное использование указателя this.

//PROG.2.1.CPP – имя файла #include<iostream> using namespace std; class myclass{ public: myclass(int n, int m){a=n; b=m;} int add(){return a+b;} void print()const; private: int a,b; } void myclass::print()const {int sum; sum= add(); cout<<”Sum = ”<<sum<<endl;} int main() { myclass ob(7,5); ob.print(); return 0; }

 

//PROG.2.2.CPP – имя файла #include<iostream> using namespace std; class myclass{ public: myclass(int n, int m){this->a=n; this->b=m;} int add(){return this->a+ this->b;} void print()const; private: int a,b; } void myclass::print()const {int sum; sum= this->add(); cout<<”Sum = ”<<sum<<endl;} int main() { myclass ob(7,5); ob.print(); return 0; }

В не константной функции-элементе add() класса myclass указатель this имеет тип myclass*const this – константный указатель на объект типа myclass. В константой функции-элементе print()const указатель this имеет тип const myclass* const this – константный указатель на константный объект типа myclass. Таким образом, константность функции распространяется только на переменные объекта, косвенно адресуемого через this функции print()const.

Указание const после аргументов функции – защита от не санкционированного изменения аргументов, т.е. использование данных только в режиме чтения.

Содержимое указателя this может возвращаться функциями класса с целью организации последовательности (сцепления) вызовов функций одного класса.

//PROG.2.3.CPP – имя файла #include<iostream> using namespace std;//множество имен, отличных от стандартных занятых языком class myclass{ public: myclass(int n, int m){a=n; b=m;} myclass& add(){c=a+b; return * this;} myclass& sub(){c=a-b; return * this;} myclass& print(int flag) { if(0 == flag) cout<<”Sum = ”<< c <<endl; else cout<<”Sub = ”<< c <<endl; return * this; } private: int a,b,c; } int main() { myclass ob(7,5); ob.add().print(0).sub().print(1); return 0; }

46. На что распространяются действия конструктора и деструктора класса?

Конструктор инициализирует объект при его создании. Он имеет такое же имя, что и сам класс, и синтаксически подобен функции. Однако в определении конструкторов не указывается тип возвращаемого значения. Формат записи конструктора такой: имя_класса () { // код конструктора } Обычно конструктор используется, чтобы придать переменным экземпляра, определенным в классе, начальные значения или выполнить исходные действия, необходимые для создания полностью сформированного объекта. Дополнением к конструктору служит деструктор. Во многих случаях при разрушении объекту необходимо выполнить некоторое действие или даже некоторую последовательность действий. Локальные объекты создаются, при входе в блок, в котором они определены, и разрушаются при выходе из него. Глобальные объекты разрушаются при завершении программы. Существует множество факторов, обусловливающих необходимость деструктора. Например, объект должен освободить ранее выделенную для него память или закрыть ранее открытый для него файл. В C++ именно деструктору поручается обработка процесса дезактивизации объекта. Имя деструктора совпадает с именем конструктора, но предваряется символом "~". Подобно конструкторам деструкторы не возвращают значений, а следовательно, в их объявлениях отсутствует тип возвращаемого значения.

 

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...