Помогни ни да направим Uroci.net по - богат! Добави урок

C++ част.7 (Член функции на клас)

C++ » C++
fix3d   трудност:    видян: 43604



Конструктори и скриване на информация

Всеки конструктор има такова ниво на дастъп до публичните, личните или защитените раздели, в които е деклариран. Например, за да ограничим използуването на класа String като буфер Stirng::strin(int) може да бъде деклариран като личен:

class Stirng {
friend class Buf;
public:
String( char* );
String();

private:
String( int ); // ... rest of Stirng class };

Единствено член функциите на String и приятелите на класа Buf могат да декларират в програмата обекти на String, които получават един аргумент от тип int. Не са наложени ограничения върху декларирането на обекти на String, които не получават аргументи или пък аргументът им е от тип char*.

f() { // ok: String::String( char* ) is public
String search( "rosebud" ); { // ok: String::String( char* ) is public
private
String inBuf( 1024 );
... }

Buf::in() // error: String::String( int ) is
String search( "rosebud" );
// ok: String::String( int ) is private
// Buf is a friend to String
String inBuf ( 4096 );
... }

Личен клас е клас без публични конструктори. Единствено член функциите и приятелите могат да декларират обекти на класа. Класът IntItem, деклариран в Раздел 5.2 е един пример за личен клас. Обектите на класа IntItem могат да бъдат дефинирани само от класа IntList, който е деклариран като приятелски на IntItem.

Деструктори

С++ поддържа един механизъм, допълващ този на конструкторите, за автоматично деинициализиране на обекти на клас. Една специална, дефинирана от потребителя член функция, наречена деструктор, се извиква, когато обектът на даден клас излиза от обхват или се приложи оператора delete към указател на клас. Когато вън от обхвата излезе псевдоним на обект на клас, обаче, деструкторът не се вика. Това се дължи на факта, че псевдонимът просто дава друго име на вече дефиниран обект; самият той не е обект на клас. Деструкторът на String се дефинира така:

class String { public:
~String();
// destructor
... };

Една член функция може да бъде дефинирана като деструктор на клас, като й се даде за име името на класа и преди него се запише тилда (“~”). Деструкторът не може да получава аргументи (и следователно не може да бъде презареждан). Той не трябва да дефинира тип за връщане или да връща стойност. Деструкторът на класа String се дефинира така:

String::~String() {delete str; }

Да припомним факта, че един конструктор фактически не отделя памет. По-скоро той служи за инициализиране на току-що отделената памет, свързана с обекта на класа. По подобие на това на практика деструкторът също не освобождава памет. Той по-скоро деинициализира обекта на класа преди освобождаването на паметта, което става когато обектът излезе от обхват. В този случай, понеже str адресира памет, отделена чрез оператора new деструкторът на String явно я изтрива. Паметта на члена на класа len, обаче, не изисква никаква специална обработка.

Няма ограничения върху това какво може да бъде правено от един деструктор. Една обща техника за тестване на програми, например, е да се постави оператор за печат както в конструкторите, така и в деструктора на класа:

String::~String() {
#ifdef DEBUG
cout << "String() " << len << " " str << "n";
#endif
delete str; }

Накратко, деструкторите могат да изпълняват всички оператори, които програмистът желае да бъдат изпълнени преди обекта на класа да излезе от обхват.

Деструкторът не се вика автoматично за указатели към обекти на клас, които са излезли от обхват. По-скоро, програмистът трябва явно да приложи операторът delete. Тогава ще бъде извикан деструктора на обекта на класа. Например,

#include "String.h"
String search( "rosebud" );
f() { // would not want destructor applied to p
String *p = &search;
// would want destructor applied to p
String *pp = new String( "sleigth" );
// ... body of f() // Sting::String() invoke for pp
delete pp; }

Ако указателят, към който е приложен операторът delete, не адресира обект на клас (т.е. има стойност 0), деструкторът не се извиква. Не е необходимо да се пише

if ( pp != 0 )
delete pp;

Има един случай, при който програмистът може да има нужда да извика деструктора явно. Това е когато той иска да изтрие обекта на класа, но не желае да освободи паметта, свързана с него. Това се случва, когато за обекта е отделена памет на определен адрес чрез използуване на оператора new. Например,

#include <string.h>
#include <stream.h>
#include <new.h>

struct inBuf { public:
inBuf( char* );
~inBuf();
private: char *st;
int sz;
};

inBuf::inBuf( char *s ) {
st = new char [ sz = strlen(s)+1 ];
strcpy( st, s );
}

inBuf::~inBuf() {
cout<<"inBuf::~inBuf(): " << st <<"n";
delete st;
}

char *pBuf = new char[ sizeof( inBuf ) ];

main() {
inBuf *pb = new (pBuf) inBuf( "free store inBuf #1" );
pb->inBuf::~inBuf();

// explicit destructor call
pb = new (pBuf) inBuf( "free store inBuf #2" );
pb- >inBuf::~inBuf();

// explicit destructor call // ... }

Когато тази програма бъде компилирана и изпълнена ще се получи следния резултат:

inBuf::~inBuf(): free store
inBuf #1 inBuf::~inBuf(): free store
inBuf #2

Явното обръщение към един деструктор изисква задаване на пълното му име. Например,


pb->inBuf::~inBuf();
// correct

pb->~inBuf();
// error


Страници: «1 2 3 4 5 6 »

Сподели урока:



Регистрирайте се, за да добавите коментар


Калдейта Ком ЕООД - © 2003-. Всички права запазени.
Препоръчваме: IT Новини