С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36
1

При создании объекта наследуемого класса не срабатывает конструктор родительского класса

19.01.2021, 01:41. Показов 2300. Ответов 10

Author24 — интернет-сервис помощи студентам
Уважаемые, эксперты! Суть простая.
1. Есть базовый класс String. В нём массив фиксированной длины, которая задана константой SZ.
При вызове ктора с аргументом типа const char[] указанный массив инициализируется (т.е. содержимое аргумента-массива копируется в массив являющийся атрибутом объекта класса)

2. Есть производный от String класс class Pstring: public String {}, который единственно что делает, - это перегружает к-тор базового класса (также с аргументом const char[]), НО УЖЕ ПРОВЕРЯЯ при этом ДЛИНУ ПОДАВАЕМОГО АРГУМЕНТА с помощью strlen. Дальше условие:
а. Если strlen(аргумента) >= SZ-1, копируем в массив объекта производного класса ТОЛЬКО (SZ-1) символ, т.е. чтобы избежать переполнения буфера отсекаем, то что не влезет
б. Иначе (т.е. strlen(аргумента)<SZ-1, а значит в исходный массив должна влезть вся строка) просто вызваю ктор родительского класса, чтоб он сам создал и проинициализировал тот же массив, т.е. копирование делать как бы незачем его
и так должен выполнить к-тор род. класса.

Проблема в том что в ветке б. передаваемое значение строки в массив объекта производного класса почему то не заносится т.е. строка выводится пустая, а значит родительский к-тор с аргументом не сработал или сработал некорректно!
Возможно срабатывает безаргументный к-тор род. класса но непонятно почему ведь вызов идёт в явном виде String(s);
В чём м.б. проблема или так вобще некорректно использовать родительский ктор?!
П.С.
Пример этот из книги Лафоре, но даже будучи скопированным один в один
нужного рез-та не возникает, как раз в том случае, когда подаваемую строку даже не надо обрезать по длине, а вот если она длинней лимита SZ всё создаётся и копируется!

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
using namespace std;
#include <string.h> //for strcpy(), etc.
 
////////////////////////////////////////////////////////////////
class String //user-defined string type
{
protected:
    static const unsigned int SZ = 10; //size of all String objects
    char str[SZ]; //holds a C-string
public:
    String() //no-arg constructor
    {
        //cout << "Suck" << endl;
        str[0] = '\0';
    }
    String(const char s[]) //1-arg constructor
    {
        strcpy_s(str, s); 
    } // convert C-string to String
    void display() const //display the String
    {
        cout << str;
    }
    operator char* () //conversion operator
    {
        return str;
    } //convert String to C-string
};
////////////////////////////////////////////////////////////////
 
 
class Pstring : public String
{
public:
    //Pstring() : String()
    //{                 }
 
    Pstring(const char s[])
    {
        if (strlen(s) >= SZ-1 ) strncpy_s(str, s, SZ-1);
        else 
        {
            
            String(s);
            //strcpy_s(str, s);
        }
    }
 
};
 
 
int main()
{
 
    Pstring ex1 = "12345678a"; // нормально работает
    cout << "ex1 = ";
    ex1.display();
    cout << endl;
 
    cout << "ex2 = ";
    Pstring ex2 = "123"; // Должно тоже инициализироваться через String(s), но почему то создаёт лишь пустую строку в 
                                      // объекте производного класса!!!
    ex2.display();
 
    return 0;
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.01.2021, 01:41
Ответы с готовыми решениями:

ООП в C++: Вызов родительского конструктора с параметром при создании объекта дочернего класса
Здравствуйте! Столкнулся с такой проблемой: если есть родительский класс с конструктором, то при...

Что значит конструкция при создании наследуемого класса от QMainWindow
Здравствуйте, подскажите пожалуйста, создал класс mainwindow, наследуемый от QMainWindow и в...

Использование объекта одного класса при создании нового класса
Добрый вечер. У меня такая проблема. Есть готовый класс L2 - список, на его основе нужно создать...

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

10
3718 / 2647 / 761
Регистрация: 29.06.2020
Сообщений: 9,800
19.01.2021, 04:07 2
Цитата Сообщение от realalexandro Посмотреть сообщение
Pstring(const char s[]) { if (strlen(s) >= SZ-1 ) strncpy_s(str, s, SZ-1); else { String(s); //strcpy_s(str, s); } }
Тут String(s); - не вызов конструктора, а создание безымянного объекта типа String.
Когда вы попали в тело конструктора Pstring, базовый класс уже создан.
Единственным мне известный способ вызова родительского конструктора - в списке инициализации наследника.
1
Вездепух
Эксперт CЭксперт С++
12794 / 6671 / 1795
Регистрация: 18.10.2014
Сообщений: 16,890
19.01.2021, 04:12 3
Цитата Сообщение от realalexandro Посмотреть сообщение
просто вызваю ктор родительского класса
В С++ вообще не существует способа явно вызвать конструктор (кроме разве что делегации конструкторов). Потому что вы имеете в виду под "просто вызваю ктор родительского класса" - не ясно. Ваше String(s); - это никакой не вызов конструктора родительского класса.
1
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36
19.01.2021, 05:40  [ТС] 4
Цитата Сообщение от SmallEvil Посмотреть сообщение
Тут String(s); - не вызов конструктора, а создание безымянного объекта типа String.
Когда вы попали в тело конструктора Pstring, базовый класс уже создан.
Единственным мне известный способ вызова родительского конструктора - в списке инициализации наследника.
Ну я так и подозревал. На самом деле меня конструкция типа String(s) уже в {} после списка инициализации тоже смущала несколько. Как будто безымянный объект род. класса возник внутри объекта класса производного. Такой не очевидный код.
Поэтому я сначала сделал также через копирование, но в решении в книге увидел именно такой более короткий ход с вызовом String(s) именно внутри тела
к-тора производного класса. Я так и стал пробовать и очень удивился, что не сработало. Книга старая, возможно старый стандарт когда то допускал такое...

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
String(s); - это никакой не вызов конструктора родительского класса.
Ну если поставить это в лист инициализации к-тора производного класса, то будет именно вызов к-тора род. класса.
Это ведь как раз то что вы имеете ввиду, когда говорите про "делегацию к-ов" или нет?
Не совсем понятно почему в теле к-тора это должно работать по-другому... Ну что ж, в любом случае это так.
Значит в листинге книги ошибка. Вот и всё тут.

Добавлено через 5 минут
Цитата Сообщение от SmallEvil Посмотреть сообщение
Когда вы попали в тело конструктора Pstring, базовый класс уже создан.
Скорее всего вы имели ввиду не класс, а объект, ибо класс же только дефиниция, а память реально выделяется только, когда объявляется объект этого класса, разве нет?
И вот я не понял, как это он такой объект род. класса м.б. уже создан при входе в к-тор Pstring, если инициализации перед скобками не было?
Ведь в производном классе у меня стоит "свой" перегруженный к-тор с входным параметром. Лист инициализации был пуст. Получается, что на момент входа в тело к-тора Pstring(const char[]) ни один из
к-торов род. класса ещё не должен был отработать...
0
Вездепух
Эксперт CЭксперт С++
12794 / 6671 / 1795
Регистрация: 18.10.2014
Сообщений: 16,890
19.01.2021, 05:44 5
Цитата Сообщение от realalexandro Посмотреть сообщение
Поэтому я сначала сделал также через копирование, но в решении в книге увидел именно такой более короткий ход с вызовом String(s) именно внутри тела
к-тора производного класса. Я так и стал пробовать и очень удивился, что не сработало. Книга старая, возможно старый стандарт когда то допускал такое...
Нет, старый стандарт никогда такого не допускал. В том смысле, что такой синтаксис всегда просто создавал временный объект.

Цитата Сообщение от realalexandro Посмотреть сообщение
Ну если поставить это в лист инициализации к-тора производного класса, то будет именно вызов к-тора род. класса.
Это будет инициализация родительского класса в списке инициализации конструктора производного класса. А то, что эта инициализация приводит в том числе к вызову конструктора родительского класса - это уже дело третье, следствие процесса инициализации.

Цитата Сообщение от realalexandro Посмотреть сообщение
Это ведь как раз то что вы имеете ввиду, когда говорите про "делегацию к-ов" или нет?
Нет. Делегация конструкторов - это фича С++11, когда конструктор класса может вызвать другой конструктор этого же класса.
1
3718 / 2647 / 761
Регистрация: 29.06.2020
Сообщений: 9,800
19.01.2021, 15:08 6
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
class A{
public:
    int a=0;
    A(int v):a(v){};};
class B:public A{
public:
    B():A{256}{};
};
 
int main()
{
    B b;
    std::cout<<b.a;
}
Я имел ввиду что вызов родительского (или даже своего) конструктора происходит на месте списка инициализации.


Не по теме:

А вызов конструктора в теле конструктора возможна в других языках.



Добавлено через 6 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нет. Делегация конструкторов - это фича С++11, когда конструктор класса может вызвать другой конструктор этого же класса.
Приведите пример.
0
1659 / 488 / 106
Регистрация: 17.05.2015
Сообщений: 1,497
19.01.2021, 15:15 7
Цитата Сообщение от SmallEvil Посмотреть сообщение
Приведите пример.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
 
struct sample
{
    sample() { std::cout << "sample();\n"; }
    sample(int)
        : sample() // делегирует инициализацию другому конструктору
    { 
        std::cout << "sample(int);\n";
    }
};
 
 
int main()
{
    sample s(1);
}
0
610 / 415 / 151
Регистрация: 11.01.2019
Сообщений: 1,746
19.01.2021, 15:35 8
Лучший ответ Сообщение было отмечено realalexandro как решение

Решение

realalexandro, всё же очевидно! У тебя конструктор производного класса неявно вызывает дефолтный конструктор базового класса, а не тот, что со строкой в параметре. Объект ex1 потом заполняется строкой, т.к. выполняется условие в строке 41, а объект ex2 остается пустым, т.к. это условие не срабатывает. В строке 45 при этом создается какой-то временный пустой объект, никак не связанный с ex1, ex2.
0
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36
19.01.2021, 17:59  [ТС] 9
Цитата Сообщение от jugu Посмотреть сообщение
realalexandro, всё же очевидно! У тебя конструктор производного класса неявно вызывает дефолтный конструктор базового класса, а не тот, что со строкой в параметре
Почему же срабатывает именно дефолтный к-тор без строки в параметре, когда инструкция идёт String(s); , а не просто String();
Я же передаю в род. к-тор именно параметр s, предполагая, что компилятор подставит, как раз родительский
НЕ дефолтный к-тор, а параметрический. Иначе зачем я передаю строку s, если она никуда не идёт?!
Я понимаю, что работает именно так, как ты описал. Не понимаю только почему хотя бы не создаётся объект род. класса,
НО ПРОИНИЦИАЛИЗИРОВАННЫЙ ИМЕННО СТРОКОЙ s!

Добавлено через 6 минут
Цитата Сообщение от jugu Посмотреть сообщение
конструктор производного класса неявно вызывает дефолтный конструктор базового класса
Или он его по-любому вызывает ещё до проверки условий? Т.е. даже если в строке инициализации производного класса
никакого к-тора явно не указано, то поскольку этот класс производный при объявлении объекта производного всегда будет
запускаться "пустой" к-тор родительского класса до любых ручных манипуляций, так я понимаю?
Ну тогда да, безымянный объект String(s) как бы повисает в пустоте и не участвует в инициализации того производного объекта, который я пытаюсь инициализировать...
0
610 / 415 / 151
Регистрация: 11.01.2019
Сообщений: 1,746
19.01.2021, 18:33 10
Цитата Сообщение от realalexandro Посмотреть сообщение
Я же передаю в род. к-тор именно параметр s, предполагая, что компилятор подставит, как раз родительский
НЕ дефолтный к-тор, а параметрический.
Увы, но компилятор такого замысла не понимает и подставляет дефолтный конструктор.

Цитата Сообщение от realalexandro Посмотреть сообщение
Ну тогда да, безымянный объект String(s) как бы повисает в пустоте и не участвует в инициализации того производного объекта, который я пытаюсь инициализировать...
Да. Это совершенно независимый временный объект базового класса.
0
Вездепух
Эксперт CЭксперт С++
12794 / 6671 / 1795
Регистрация: 18.10.2014
Сообщений: 16,890
19.01.2021, 19:09 11
Цитата Сообщение от realalexandro Посмотреть сообщение
Почему же срабатывает именно дефолтный к-тор без строки в параметре, когда инструкция идёт String(s); , а не просто String();
Не понял. Какой конструктор базового класса будет вызван определяется списком инициализации класса-населдника. У вас там нет вообще никаких "инструкций" для базового класса. Потому и вызывается конструктор по умолчанию.

Цитата Сообщение от realalexandro Посмотреть сообщение
Я же передаю в род. к-тор именно параметр s, предполагая, что компилятор подставит, как раз родительский
НЕ дефолтный к-тор, а параметрический. Иначе зачем я передаю строку s, если она никуда не идёт?!
Вы о чем? О вашем String(s); в теле конструктора? Как же было сказано выше, это создание постороннего временного объекта типа String. Все тут прекрасно передается, вызывается конструктор String(const char s[]). О каком "никуда не идёт" вы ведете речь?

Цитата Сообщение от realalexandro Посмотреть сообщение
Я понимаю, что работает именно так, как ты описал. Не понимаю только почему хотя бы не создаётся объект род. класса, НО ПРОИНИЦИАЛИЗИРОВАННЫЙ ИМЕННО СТРОКОЙ s!
Откуда вы это взяли? Все прекрасно создается! Создаётся временный объект родительского класса, проинициализированный именно строкой s. После чего он сразу же удаляется. Это посторонний временный объект, который в вашем коде ни на что не влияет.
0
19.01.2021, 19:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.01.2021, 19:09
Помогаю со студенческими работами здесь

Ошибка при создании объекта класса
Привет! Чтобы на протяжении всего поста было понятно о чём я говорю,в конце поста прикреплю код....

Ошибка при создании объекта класса
Есть класс, создаю объект, выходит ошибка &quot;cannot allocate an object of abstract type 'Cat'&quot; Что...

Ошибка при создании объекта класса
Приветствую, форумчане! Возник вопрос при создании объекта класса String. Что самое интересное,...

Ошибка при создании объекта класса
Здравствуйте. В коде ниже при попытке вывести код на экран возникает следующая ошибка: prog.cpp:...

Не могу передать параметр в родительский конструктор при создании экземпляра класса
Хочу создать экземпляр класса Human, и передать в конструктор его родительского класса параметр...

Конструктор родительского класса с аргументом
abstract class Animal { private String name; public String getName() { return name; }...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru