Упражнение 14.9
Какие из приведенных инструкций неверны? Исправьте их.
(a) Account *parray[10] = new Account[10];
(b) Account iA[1024] = {
"Nhi", "Le", "Jon", "Mike", "Greg", "Brent", "Hank"
"Roy", "Elena" };
(c) string *ps=string[5]("Tina","Tim","Chyuan","Mira","Mike");
(d) string as[] = *ps;
Упражнение 14.10
Что лучше применить в каждой из следующих ситуаций: статический массив (такой, как Account pA[10]), динамический массив или вектор? Объясните свой выбор.
Внутри функции Lut() нужен набор из 256 элементов для хранения объектов класса Color. Значения являются константами.
Необходимо хранить набор из неизвестного числа объектов класса Account. Данные счетов читаются из файла.
Функция gen_words(elem_size) должна сгенерировать и передать обработчику текста набор из elem_size строк.
Упражнение 14.11
Потенциальным источником ошибок при использовании динамических массивов является пропуск пары квадратных скобок, говорящей, что указатель адресует массив, т.е. неверная запись
// печально: не проверяется, что parray адресует массив
delete parray;
вместо
// правильно: определяется размер массива, адресуемого parray
delete [] parray;
Наличие пары скобок заставляет компилятор найти размер массива. Затем к каждому элементу по очереди применяется деструктор (всего size раз). Если же скобок нет, уничтожается только один элемент. В любом случае освобождается вся память, занятая массивом.
При обсуждении первоначального варианта языка С++ много спорили о том, должно ли наличие квадратных скобок инициировать поиск или же (как было в исходной спецификации) лучше поручить программисту явно указывать размер массива:
// в первоначальном варианте языка размер массива требовалось задавать явно
delete p[10] parray;
Как вы думаете, почему язык был изменен таким образом, что явного задания размера не требуется (а значит, нужно уметь его сохранять и извлекать), но скобки, хотя и пустые, в операторе delete остались (так что компилятор не должен запоминать, адресует указатель единственный объект или массив)? Какой вариант языка предложили бы вы?
14.5. Список инициализации членов
Модифицируем наш класс Account, объявив член _name типа string:
#include string
class Account {
public:
// ...
private:
unsigned int _acct_nmbr;
double _balance;
string _name;
};
Придется заодно изменить и конструкторы. Возникает две проблемы: поддержание совместимости с первоначальным интерфейсом и инициализация объекта класса с помощью подходящего набора конструкторов.
Исходный конструктор Account с двумя параметрами
Account( const char*, double = 0.0 );
не может инициализировать член типа string. Например:
string new_client( " Steve Hall" );
Account new_acct( new_client, 25000 );
не будет компилироваться, так как не существует неявного преобразования из типа string в тип char*. Инструкция
Account new_acct( new_client.c_str(), 25000 );
правильна, но вызовет у пользователей класса недоумение. Одно из решений - добавить новый конструктор вида:
Account( string, double = 0.0 );
Если написать:
Account new_acct( new_client, 25000 );
вызывается именно этот конструктор, тогда как старый код
Account *open_new_account( const char *nm )
{
Account *pact = new Account( nm );
// ...
return pacct;
}
по-прежнему будет приводить к вызову исходного конструктора с двумя параметрами.
Так как в классе string определено преобразование из типа char* в тип string (преобразования классов обсуждаются в этой главе ниже), то можно заменить исходный конструктор на новый, которому в качестве первого параметра передается тип string. В таком случае, когда встречается инструкция:
Account myAcct( " Tinkerbell" );
" Tinkerbell" преобразуется во временный объект типа string. Затем этот объект передается новому конструктору с двумя параметрами.
При проектировании приходится идти на компромисс между увеличением числа конструкторов класса Account и несколько менее эффективной обработкой аргументов типа char* из-за необходимости создавать временный объект. Мы предоставили две версии конструктора с двумя параметрами. Тогда модифицированный набор конструкторов Account будет таким:
#include string
class Account {
public:
Account();