Страницы

Поиск по вопросам

четверг, 28 марта 2019 г.

Вызов конструктора без аргументов?

Здравствуйте. Решаю 2 задачу 9 главы из книги Р. Лафоре. Наткнулся на проблему. Задача: Вспомните пример STRCONV из главы 8. Класс String в этом примере имеет дефект: у него нет защиты на тот случай, если его объекты будут инициализированы слишком длинной строкой (константа size имеет значение 15). Например: String s = "Эта строка имеет очень большую длину и мы можем быть уверены, что она не уместится в отведенный буфер, что приведет к непредсказуемым последствиям."; будет причиной переполнения массива str строкой s с непредсказуемыми последствиями вплоть до краха системы. Создадим класс Pstring, производный от класса String, в котором предотвратим возможность переполнения буфера при определении слишком длинной строковой константы. Новый конструктор производного класса будет копировать в str только size-1 символов, если строка окажется слишком длинной, и будет копировать строку полностью, если она будет иметь длину меньшую, чем size. Напишите функцию main() программы для проверки ее работы со строками разной длины.
#include #include
const int size = 15;
class String { protected: char str[size]; public: String () { str[0] = '\x0'; } String (const char* s) { strcpy(str, s); std::cout << "Скопировано: " << str << std::endl; } void display () const { std::cout << str << std::endl; } operator char* () { return str; } };
class Pstring : public String { public: Pstring (char* s) { if (strlen(s) >= size) { for (int index = 0; index < size - 1; ++index) { str[index] = s[index]; } str[strlen(str)] = '\x0'; } else { String(s); // почему не копируется строка, а вызывается конструктор без аргументов? } } };
int main () { Pstring p1 = "pointers is evil!!!"; p1.display (); Pstring p2 = "char * is bad"; p2.display();
return 0; }
При определении переменных класса Pstring вначале вызывается конструктор по умолчанию String::String(); до выполнения блока. Далее, идёт проверка на длину строки. Вопрос: Почему, если строка меньшего размера, то при вызове конструктора String(s); в ветви else не копируется значение строки? Почему на выводе пустая строка.


Ответ

У вас имеется несколько проблем с определением конструкторов в классе Pstring. Во-первых, желательно, чтобы он вел себя как класс String, что означает, что он также должен иметь конструктор по умолчанию.
Pstring() {}
Во-вторых, вами определенный конструктор с параметром полностью неверный.
В этом предложении конструктора
str[strlen(str)] = '\x0';
присутствуют сразу же две ошибки. Строка str не имеет пока еще завершающего нуля, поэтому вызов strlen( str ) ведет к неопределенному поведению. К тому же вы должны установить в 0 символ в позиции size - 1
В этом предложении
String(s);
У вас создается временный объект, который сразу же удаляется в конце предложения. Он никак не связан с тем объектом, в конструкторе которого вызывается это предложение.
Имейте в виду, что когда вы имеете дело со строками, а тем более со стандартными C функциями, предназначенными для работы со строками, то лучше в качестве индекса в строках использовать тип size_t вместо типа int
Также в качестве параметра конструктора следует задать параметр с типом const char *, так как, как по крайней мере следует из вашей программы, конструктор может иметь дело со строковыми литералами в качестве аргументов, а строковые литералы в C++ в выражениях преобразуются (за редким исключением) к типу const char *
Далее длина члена класса str - это внутреннее свойство самого класса. Поэтому его длина не должна быть глобальной переменной.
И, наконец, желательно, чтобы деструктор был виртуальным.
Я бы определили данные классы следующим образом
class String { protected: static const size_t size = 15; char str[size];
public: String () { str[0] = '\x0'; } String (const char* s) { std::strcpy(str, s); std::cout << "Скопировано: " << str << std::endl; } virtual ~String() {} void display () const { std::cout << str << std::endl; } operator const char* () const { return str; } };
class Pstring : public String { public: Pstring() {} Pstring ( const char* s) { if ( std::strlen(s) < size) { std::strcpy( str, s ); } else { size_t i = 0; for ( ; i < size - 1; ++i) { str[i] = s[index]; } str[i] = '\x0'; // или просто //std::strncpy( str, s, size - 1 ); // str[size-1] = '\0'; } } };

Комментариев нет:

Отправить комментарий