Фиг. 7.2 Програмен
пример за използуване на BitVector
#ifndef BITVECTOR_H
#define
BITVECTOR_H
#ifdef vax
const BITSPERBYTE = 8;
const
BYTESPERWORD = 4;
#endif
#ifdef sunconst BITSPERBYTE =
8;
const BYTESPERWORD = 2;
#endifconst WORDSIZE = BITSPERBYTE *
BYTESPERWORD;
enum { OFF, ON };
typedef unsigned int
BitVecType;
typedef BitVecType *BitVec;
#include
<iostream.h>
class BitVector
{friend
ostream&operator<<( ostream&, BitVector&
);
public:
BitVector( int = WORDSIZE, int = OFF
);
~BitVector() { delete [wordWidth] bv; }
void operator+=( int
pos ); // turn on pos
void operator-=( int pos ); // turn off
pos
BitVector operator &( BitVector& );
BitVector operator
|( BitVector& );
operator == ( int pos ); // pos is
on
operator != ( int pos ); // pos is off
void reset(); // reinit
to 0 private: // helping functions
void checkBounds( int );
inline
getOffset( int );
inline getIndex( int );
private: // internal
representation short wordWidth;short size;
BitVec
bv;
};
#indif
Фиг. 7.3 BitVector.h
Упражнение 7-26.
Променете представителя на оператора за изход на BitVector така че да сгъстява
последователните битове с еднаква стойност. Например, ако текущия изход
е:
< 0, 1, 2, 3, 4, 5, 6, 7 >< 0, 2, 3, 4, 7, 8, 9, 12
>
Реализирайте оператора за изход така че да групира последователните
стойности като отделена с тире двойка. Например,
< 0 - 7 >
<
0, 2 - 4, 7 - 9, 12 >
7.5. Конвертори, дефинирани
от потребителя
Предварително дефинираните стандартни конвертори за
вградените типове данни предотвратяват комбинаторния взрив от оператори и
презаредими функции. Например, без аритметичните конвертори следните шест
операции събиране ще изискват уникални реализации:
char ch;
short
sh;
int ival;// widout type conversion, each addition
// would require a
unique operationch + ival;
ival + ch;ch + sh;
sh + ch;ival + sh;
sh +
ival;
Чрез аритметичните конвертори всеки операнд се преобразува към типа
int. Необходима е само една операция - за събиране на две цели стойности. Тези
преобразувания се обработват неявно от компилатора и следователно са прозрачни
за потребителя.
В този раздел ще разгледаме как проектантът на един клас
може да предложи набор от конвертори за класа. Тези конвертори се извикват
неявно от компилатора когато е необходимо. За да илюстриране на нашето обсъждане
ще реализираме класа SmallInt.
Класът SmallInt може да поддържа стойности
от един и същ обхват като 8-битови unsigned char - т.е. 0 - 255. Допълнителни
възможности са, че се откриват грешки, свързани с малки и големи числа, излизащи
извън обхвата. Иначе, искаме класът да се държи по същия начин както и unsigned
char. Например, ние бихме желали да добавяме и изваждаме обекти на SmallInt
помежду си или с вградените аритметични типове. За поддържането на тези операции
трябва да реализираме шест оператор функции на SmallInt:
class
SmallInt
{
friend operator+( SmallInt&, int );
friend operator-(
SmallInt&, int );
friend operator-( int, SmallInt& );
friend
operator+( int, SmallInt& );public:
operator+( SmallInt&
);
operator-( SmallInt& );// ...};
Необходими са само шест
оператора понеже вградените аритметични типове ще бъдат конвертирани за да
съответствуват на операнд от тип int. Например, изразът
SmallInt si( 3
);si + 3.14159
се изчислява на две стъпки:
1. Константата от тип
double 3.14159 се преобразува до цялата стойност 3.
2. Извиква се
operator+(si,3), който връща стойност 6.
Ако също така желаем да бъдат
поддържани побитови, логически, релационни и съставни оператори за присвояване
броят на необходимите оператори става направо обезсърчаващ. Вместо това ние ще
предпочетем един начин за преобразуване на обекти на класа SmallInt към
int.
С++ предлага механизъм чрез който всеки клас може да дефинира набор
от конвертори, които да могат да бъдат прилагани над обектите на класа. За
SmallInt ще дефинираме конвертор за обект на SmallInt към тип int. Ето
реализацията:
class SmallInt
{
public:// conversion
operator:
SmallInt ==> int operator int() { return value; }
//
...private:
int value;};
Конверторите, дефинирани от потребителя, за
типа клас предлагат набор от правила за преобразуване на обекти на класа. Те
дефинират позволените преобразувания, които могат да бъдат изпълнявани върху
конкретни обекти на класа. Освен това те определят какво означава за компилатора
преобразуванието. Един обект на класа SmallInt вече може да бъде използван
навсякъде, където може да бъде използуван обект от тип int. Например,
изразът
SmallInt si( 3 );si + 3.14159;
сега се изпълнява на
следните две стъпки:
1. Извиква се оператора конвертор на SmallInt, който
дава цялата стойност 3.
2. Цялата стойност 3 се преобразува до 3.0 е се
събира с константата от тип double 3.14159, кото се получава стойност
6.14159.
Слeдната програма илюстрира използуването на класа
SmallInt:
#include <stream.h>
#include "SmallInt.h"
SmallInt
si1, si2;
main() {
cout << "enter a SmallInt, please: ";
while (
cin >> si1 )
{ cout << "nnThank you.n";
cout << "The
value read is "<< si1 << "nIt is ";//
SmallInt::Operator int()
invoked twice cout << (( si1 > 127 )
? "greater than ": (( si1 <
127 )?
"less than ": "equal to ")) << "127n";
cout <<
"nenter a SmallInt, please (ctrl-d to exit): ";
}
cout << "bye
nown";}
Когато компилираме и изпълним тази програма ще получим следния
резултат:
enter a SmallInt, please: 127
Thank you.
The value read
is 127
It is equal to 127 enter a SmallInt, please (ctrl-d to exit):
126
Thank you.
The value read is 126
It is less to 127
enter a
SmallInt, please (ctrl-d to exit): 128
Thank you.
The value read is
128
It is greater to 127
enter a SmallInt, please (ctrl-d to exit):
256
***SmallInt range error: 256 ***
Реализацията на класа SmallInt
изглежда така:
#include <stream.h>
class SmallInt {
friend
istream&operator>>(istream& is, SmallInt& s);
friend
ostream&operator<<(ostream& os, SmallInt& s)
{ return ( os
<< s.value ); }
public:SmallInt(int i=0) : value(rangeCheck(i)
);
}
int operator=(int i)
{ return( value = rangeCheck(i) );
}
operator int() { return value; }
private:
enum { ERRANGE = -1
};
int rangeCheck( int );
int error( int );
int
value;
};
Член функциите, дефинирани вън от тялото на класа изглеждат
така:
istream& operator>>( istream& is, SmallInt& si
)
{
int i;
is >> i;
si = i; //
SmallInt::Operator=(int)
return is;}
SmallInt::error( int i
)
{
cerr << "n***SmallInt range error: "<< i << "
***n";
return ERRANGE;}ю
SmallInt::rangeCheck( int i )
{// if any bits
are set other than the first 8
// value is too large: report, then exit
if
( i & ~0377 )exit( error( i ) ); // stdlib.h
return i;}
Упражнение
7-27. Защо презаредимият оператор за вход не е реализиран по следния
начин?
istream& operator>>( istream& is, SmallInt & si
)
{return ( is >> si.value );}