ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Categories:

Конструктор базового класса в теле производного

Одна из редких ошибок в оригинале учебника Лафоре. Выношу фрагмент программы со стр.946 (цитата неточная, но смысл ошибки передает):

// базовый класс
class String
{
protected:
    static const int SZ = 80;
    char str[SZ];
public:
    String()               // конструктор базового класса
        { str[0] = '\0'; }
    String(const char s[]) // еще один конструктор базового класса
        { strcpy(str, s); }
};

// производный класс
class Pstring : public String
{
public:
    Pstring(const char s[]); // объявление конструктора
};                           // производного класса

Pstring::Pstring(const char s[]) // реализация конструктора
{                                // производного класса
    if (strlen(s) > SZ - 1)
    {
        int j;
        for (j = 0; j < SZ - 1; j++)
            str[j] = s[j];
        str[j] = '\0';
    }
    else
        String(s); // собственно, ошибка
}

Вот здесь свежее (март 2019 г.) обсуждение:
http://www.cyberforum.ru/cpp-beginners/thread2425673.html

Обсуждение — атомное: от мнения, что книжка Лафоре — «неиссякаемый источник кульков для семечек», до полного экстаза в виде пожелания «ставиться ею по вене».

Сначала о том, что это вообще за программа. Данная программа не имеет большого практического смысла, ее назначение чисто учебное. По условиям упражнения (упражнение 2 к главе 9, стр.424 оригинала) имеется базовый класс и его нельзя изменять. Ученик должен написать производный класс, в котором (конкретно в конструкторе с одним параметром) требуется выполнить дополнительные проверки для заданного параметра. В приложении G учебника на стр.946 как раз и дается возможная программа-решение этого упражнения с указанной ошибкой.

Смысл решения. Конструктору производного класса задается в качестве параметра строка в виде массива символов. Если эта строка по длине не укладывается в размер SZ, то в поле str базового класса копируется только часть заданной строки размером SZ - 1 (последнее место в массиве символов оставлено для нулевого символа '\0', означающего конец строки). Если же заданная строка укладывается в размер SZ, то (ошибка) вызывается конструктор базового класса, в который и передается заданная строка.

В чем ошибка. Как я понимаю, из тела конструктора производного класса нельзя вызвать конструктор базового класса. Это нарушило бы принцип, по которому конструктор базового класса должен завершить свою работу перед началом работы конструктора производного класса.

Конструктор базового класса может быть вызван в конструкторе производного класса только в списке инициализации членов класса.
Pstring::Pstring(const char s[]) : String(s) // так можно
{
    String(s);         // не является вызовом конструктора базового класса

    String::String(s); // не является вызовом конструктора базового класса
                       // для текущего объекта
}
Оператор String(s); в теле этого конструктора — то же самое, что и String s;, то есть объявление нового объекта класса String. К объекту, для которого вызван конструктор производного класса, этот новый объявленный объект не имеет никакого отношения, а значит, хоть программа отработает без технических ошибок, но она всё же отработает не так, как планировалось.

Что делать. Для процитированного в начале поста фрагмента кода проще всего заменить String(s); на strcpy(str, s);.

А вообще можно создать отдельный метод, в котором и выполнить необходимые проверки, а затем при обращении в списке инициализации членов класса к конструктору базового класса вызвать этот метод для параметра. Например:
Pstring::Pstring(const char s[]) : String(test(s))
{ }

const char* Pstring::test(const char s[])
{
    // здесь выполнить проверки
}

Вот тут еще близко к этой теме пишут:
https://ravesli.com/urok-119-delegiruyushhie-konstruktory/
Tags: Образование, Программирование
Subscribe

  • JavaScript: Blob

    Прочел подраздел 2.3 « Blob» третьей части учебника по JavaScript. Для меня эта статья оказалась настолько объемной в плане нового, что ее разбор…

  • Сказка про двоичные данные, кодировку Windows-1251 и Юникод

    Вопрос из комментариев к подразделу 2.3 « Blob» третьей части учебника по JavaScript, цитата: Не могу найти способ выдавать файл с кодировкой…

  • Как работает кодирование Base64, окончание

    Начало: « Как работает кодирование Base64». Пример второй. « Картинка-смайлик» В предыдущем примере кусок двоичных данных, содержащий текст,…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments