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

C++ част.5 (Свободна памет)

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



Литералната константа е от тип double. Тя не съответства точно на нито един представител. С двата представителя се постига съпоставяне чрез прилагане на стандартните преобразувания. Понеже съществуват две възможни преобразувания обръщението се отбелязва като двусмислено. На нито едно стандартно преобразувание не се дава приоритет спрямо друго. Програмистът трябва да разреши проблема с двусмислието или чрез явно конвертиране, такова като

ff( long( 3.14 )); // ff(long)

или като използва суфикс за означаване на константа float

ff( 3.14F ); // ff(float)

В следния пример, където са дадени следните декларации

ff( unsigned );
ff( int );
ff( char );

обръщение с фактически аргумент от тип unsigned char се съпоставя на формален аргумент от тип int. Другите два преставителя изискват прилагането на стандартни преобразувания.

unsigned char uc;
ff( uc ); // ff(int)

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

extern void ff( const char* ); // ff( const char* )
ff( cp );
extern void ff( char* ); // ff( const char* )

ff( cp );
char *cp;
const char *pcc;
ff( pcc ); // error ambiguous

Последното обръщение е двусмислено понеже 0 точно съответствува на тип int. Но тя може да се съпостави също и на представителя на ff() чрез прилагане на стандартно преобразуване. Преобразуването на 0 към тип указател прави съпоставими двата представителя на ff().

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

enum Bool { FALSE, TRUE } found;
enum Stat { FAIL, PASS };
extern void ff( Bool );
extern void ff( Stat );
extern void ff( int );

ff( PASS ); // ff( Stat )
ff( 0 ); // ff( int )
ff( found ); // ff( Bool )

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

extern vоid ff(int);
extern void ff(void *);

и обръщението

ff( 0xffbc );

съответства на ff(int) точно, понеже 0xffbc е цяла литерална константа, написана в шестнадесетичен вид. Програмистът може да предизвика обръщение към void* представителя на ff(), обаче, като приложи явно преобразуване. Това може да се направи така

ff( (void ) 0xffbc ); // ff(void )

Явното преобразуване на фактическия аргумент осигурява точното съпоставяне на аргумента с типа на преобразуването.



Особености на съпоставянето чрез стандартно преобразуване.

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

extern ff( char* );
extern ff( ddouble );
ff( ‘a’ ); // ff( double );

При прилагане на стандартни преобразувания на типовете към фактическите аргументи на обръщението към функцията

1. произволен числов тип ще бъде съпоставен на формален аргумент от който и да е друг числов тип, включително и unsigned;

2. изброимите типове ще бъдат съпоставени на формални аргументи от числов тип;

3. нулата ще бъде съпоставена както на формален аргумент от тип указател, така и на формален аргумент от числов тип;

4. указател от произволен тип ще бъде съпоставен на формален аргумент void*.

Ето няколко примера

extern ff( char* );
extern ff( void* );
extern ff( double );
main() {
int i;
ff( i ); // matches ff( double );
ff( &i ); // matches ff( void* );
ff( "a" ); // matches ff( char* );
}

Всички стандартни преобразувания се разглеждат като изискващи еднаква работа. Преобразуването от char към unsigned char, например, няма по-висок приоритет спрямо преобразуването char към double. Близост на типовете не се разглежда. Ако е възможно повече от едно съпоставяне при прилагането на стандартните преобразувания обръщението е двусмислено и се отбелязва от компилатора като грешно. Например, нека е дадена следната двойка от презаредими функции

extern ff( unsigned );
extern ff( float );

и всяко от следните обръщения е съпоставимо на всеки от двата представителя. Всяко от обръщенията е двусмислено и се отбелязва като грешно.

// each call is ambiguous
ff( ‘a’ );
ff( 0 );
ff( 2uL );
ff( 3=14159 );

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



Съпоставяне на аргументи псевдоними (reference)

Винаги, когато даден аргумент псевдоним се изпраща като стойност за четене (rvalue) или като идентификатор, чийто тип не съответствува точно на типа на псевдонима се генерира временна променлива. (Раздел 5.7 разглежда генерирането на временни променливи за аргументите псевдоними). В случая, когато са възможни две или повече стандартни преобразувания за свързването на обръщение към презаредима функция, приоритет има преобразуванието, което не изисква генерирането на временен обект пред това, което изисква.

В следващото обръщение, например, за да бъде направено съпоставяне е необходимо прилагане на стандартно преобразуване и за двата представителя. Преобразуването на int към short, обаче, не изисква генериране на временен обект, докато преобразуването към char& изисква. Преобразуването към short, следователно, има приоритет. В този случай няма двусмислие.

extern ff( char& );
extern ff( short );
int i;
ff( i ); // ff(short), standart conversion

Ако, обаче, аргументът от тип short също беше деклариран като псевдоним обръщението ще бъде двусмислено, тъй като и двата представителя ще изискват генерирането на временен обект. Забележете, че генерирането на временен обект не се взема под внимание в случая на точно съпоставяне

ff( ‘a’ ); // ff(char&), exact match


Обръщения, съдържащи множество аргументи

Едно обръщение, съдържащо множество аргументи се свързва, като последователно се прилагат правилата за съпоставяне. Избира се тази функция, за която свързването на аргументите е същото или по-добро от това за останалите функции от презаредимото множество. Например,

extern ff( char*, int );
exetrn ff( int, int );// ff( int, int )
ff( 0, ‘a’ );

Извиква се представителя на ff(), който получава два аргумента от тип int, понеже:

1. Съпоставянето на първия аргумент е максимално добро. 0 точно отговаря на формалния аргумент от тип int.
2. При втория аргумент имаме еднаквост. ‘a’ в една и съща степен съответствува на втория аргумент на двете функции.

Едно обръщение се счита за двусмислено ако няма представител, който да е съпоставим максимално добре. В следния пример и за двата представителя е необходимо да бъдат извършени стандартни преобразувания за да се получи съпоставяне

int i, j;
extern min ( long, long );
extern min ( double, double );// error amabiguous, no "best" match

min( i, j );

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

extern foo( int, int );
extern foo( double, double );
// error ambiguous two "best" matches
foo( ‘a’, 3.14F );

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



Аргументи с подразбиращи се инициализатори

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

extern ff( int );
extern ff( long, int = 0 );
main() {
ff( 2L ); // matches
ff( long, 0 );
ff( 0, 0 ); // matches
ff( long, int );
ff( 0 ); // matches
ff( int );
ff( 3.14 ); // error ambiguous
}

Последното обръщение е двусмислено, понеже могат да бъдат съпоставени и двата представителя чрез прилагане на стандартни преобразувания. Няма зададен приоритет за ff(int) понеже, тя има точно един аргумент.



Презареждане и обхват

Всяко презаредимо множество от функции, свързано с определено име, трябва да бъде декларирано в един и същ обхват. Една локално декларирана функция, например, по-скоро скрива, отколкото да се презарежда като представител на функция, декларирана с файлов обхват. Например,

extern void print( char* );
extern void print( double ); // ovoerloads print
void fooBar( int ival ) {
// separate scope hides both instances of print
extern void print( int );
print("Value ");// error print(char*) is not visible in this scope
print( ival ); // ok
print(int);
}

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

Упражнение 5-8. Как трябва да бъде дефинирана функцията error() за да обработва следните обръщения

error( "Array out of bounds ", index, upperBound );
error( "Division by zero" );
error( "Invalid selection", selectVal );





Презареждане на оператора new

Операторът new може да бъде презареждан от програмиста. Предварително дефинираният негов представител има следния прототип

void *operator new( long size );

където size указва паметта в байтове, необходима на типа. Всеки представител на new, дефиниран от потребителя, трябва да връща void* и да определя първия се аргумент от тип long. Например, един втори презаредим представител на оператора new се предлага от една от стандартните за С++ библиотеки. Нейният прототип изглежда така

void * oprerator new( long size, void *memAddress );

Аргументът size се предлага автоматично от компилатора. Допълнителният аргумент трябва да бъде зададен чрез списък от аргументи, разделени със запетая, поместен между ключовата дума new и спецификатора на тип.

#include <new.h>

char buf[ sizeof(IntArray) ];
main() {
// default instance of new
IntArray *pa = new IntArray( 10 );

// operator new( long, void* )
IntArray *pbuf = new (buf) IntArray( 10 );
}


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

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



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


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