Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.95/64: Рейтинг темы: голосов - 64, средняя оценка - 4.95
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654

Инициализация полей класса при наследовании

13.03.2017, 23:54. Показов 13495. Ответов 38
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем добрый вечер.
Возникла у меня небольшая задачка, которую никак не могу решить.
Имеем базовый класс с константным полем:
C++
1
2
3
4
5
6
class A{
public:
    A() {}
protected:
    const int   field;
};
Имеем наследника :
C++
1
2
3
4
5
class B: public A{
public:
    B() {}
    
};
Задача. При создании экземпляра наследника, необходимо проиницилизировать поле field.
Пытаюсь сделать так :
C++
1
2
3
4
5
class B: public A{
public:
    B(): field(1000) {}
    
};
, но не выходит каменный цветочек. Компилятор (g++) на меня сильно материться. Мол нет в классе 'B' поля 'field' :
error: class 'B' does not have any field named 'field'
Хотя, если поле не константа, то в конструкторе класса 'B' я свободно пишу
C++
1
field=1000;
и компилятор это одобряет.

Люди, скажите, пожалуйста, что ему не нравится ? И как можно проинициализировать константное поле в наследнике ?

Спасибо.
1
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
13.03.2017, 23:54
Ответы с готовыми решениями:

Инициализация при множественном наследовании
Имеется иерархия типов. Во главе: базовый класс-интерфейс, далее один базовый класс, от него два производных, а от них множественно...

Инициализация полей класса
Приветствую всех. Не в одной книге по С++ сказано, что поля класса желательно инициализировать в списке инициализации конструктора этого...

Инициализация полей во время объявления класса
Инициализировать поля класса во время его объявления возможно только если в классе отсутствует конструктор? По каким то ещё принципам можно...

38
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 00:01
Цитата Сообщение от alkl Посмотреть сообщение
Люди, скажите, пожалуйста
возможно вам станет понятнее если вы в классе B создатите переменную с именем field - получается конфликт имёт по вашей логике, и field имя нельзя создавать в классе В

Ничего не смущает, что в С++ у наследников нельзя создавать имена переменных как у класса родителя?!?!


А теперь по делу!
Родитель создается в момент вызова конструктора А, он у вас вызывается неявно до вызова инициализации переменной field которой нету в В

Таблетка:

C++
1
B() : A(1255)
где у класса А есть конструктор инициализирующий свои поля
2
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 00:12  [ТС]
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
возможно вам станет понятнее если вы в классе B создатите переменную с именем field - получается конфликт имёт по вашей логике, и field имя нельзя создавать в классе В
Ничего не смущает, что в С++ у наследников нельзя создавать имена переменных как у класса родителя?!?!
Я и не создаю копию поля в B-классе, знаю что будет конфликт.

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Родитель создается в момент вызова конструктора А, он у вас вызывается неявно до вызова инициализации переменной field которой нету в В
Тут вообще ничего не понял. Кто и когда вызывается, до какой инициализаци, почему переменной нету, если она есть, ...

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Таблетка:
Сложно, конечно, это назвать "таблеткой", но как вариант - пойдёт. Спасибо.
Всё равно не то, что хотелось бы...
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 00:22
Вот еще пример
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
#include <iostream>
#include "Some1.h"
using namespace std;
 
class SecretBase
{
protected:
    const int m_code = 17;
public:
    SecretBase( const int am )
        : m_code( am )
    {
    }
};
 
class Secret : public SecretBase
{
public:
    Secret() : SecretBase( 55 )
    {
    }
};
 
 
class CustumSecret : public Secret
{
private:
    int m_code;
 
public:
    CustumSecret()
        : m_code( Secret::m_code + 1000)
    {
    }
    int getSecret() const
    {
        return m_code;
    }
};
 
 
int main()
{
    CustumSecret secret;
    cout << secret.getSecret() << endl;
}
Добавлено через 1 минуту
Цитата Сообщение от alkl Посмотреть сообщение
Тут вообще ничего не понял. Кто и когда вызывается, до какой инициализаци, почему переменной нету, если она есть, ...
Да она есть - но она уже создана и должна была быть инициализирована!

Цитата Сообщение от alkl Посмотреть сообщение
Всё равно не то, что хотелось бы...
Учитывая то как вы описали вашу проблему - я с радостью всё вам объясню по 100 раз.

Задайте ряд вопросов - всё разберём!

Добавлено через 4 минуты
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
#include <iostream>
#include "Some1.h"
using namespace std;
 
 
class SomeVar
{
public:
    SomeVar( int f )
    {
        cout << "I am some var with " << f << endl;
    }
};
 
class MustBeInited
{
private:
    int m_x;
public:
    MustBeInited()
    {
        cout << "Dont inited" << endl;
    }
    MustBeInited( int x ) 
        : m_x(x)
    {
        cout << "Already inited with " << x << endl;
    }
};
 
 
class A
{
protected:
    const MustBeInited m_some;
};
 
class B : public A
{
private:
    SomeVar m_some;
 
public:
    B() : m_some( 14 )
    {
 
    }
};
 
int main()
{
    {
        B b;
    }
    cout << "Hello world" << endl;
}
Добавлено через 1 минуту
Цитата Сообщение от alkl Посмотреть сообщение
Я и не создаю копию поля в B-классе, знаю что будет конфликт.
конфликт разрешаемый при явном указании к какому m_var мы обращаемся - я не зря там указал фразу "по вашей логике"
1
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 00:24  [ТС]
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Вот еще пример
Ну, собственно, это то, что Вы раньше назвали "таблеткой". Это я уже понял...

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Да она есть - но она уже создана
Не понятно, почему она уже создана (ещё до создания экземпляра класса 'B'). Ведь, по сути, класса 'A', фактически не существует, и при создании экземпляра класса 'B', создаётся именно его экземпляр, в котором существуют все переменные, находящиеся в 'A'. Грубо говоря, просто копируются. Тогда не понятно, почему её нет в 'B'.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 00:28
Цитата Сообщение от alkl Посмотреть сообщение
Не понятно, почему она уже создана
Пример с MustBeInited() - он вызывается до SomeVar( int f )

Цитата Сообщение от alkl Посмотреть сообщение
Ведь, по сути, класса 'A', фактически не существует, и при создании экземпляра класса 'B'
Это не верно. Фактическим называется то, что можно потрогать. Вам привести пример где можно обращаться к полям родителя или его методам? Он есть - но поглащён классом Б как наследник.

Цитата Сообщение от alkl Посмотреть сообщение
Грубо говоря, просто копируются.
Тоже не верно. При "грубом копировании" не вызывался бы конструктор родителя как полноценного объекта.

Цитата Сообщение от alkl Посмотреть сообщение
Тогда не понятно, почему её нет в 'B'.
Класс А есть в классе Б - можно ведь обратиться к полям на чтение и запись!
1
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 00:53  [ТС]
Мда... Я начинаю понимать, что и ничего не понимаю...

Попробую описать общую задачу.
Имеем базовый класс. У него есть свой конструктор. Он вызывается раньше всех производных конструкторов - в этом, как раз у меня и проблема. Мне необходимо, создавая наследника, проинициализировать переменную раньше, чем вызовется конструктор базового класса.
Для примера :
C++
1
2
3
4
5
6
7
8
9
10
class A{
public:
    A(){
        var=var_init;   // Тут нужно, чтобы 'var_init' уже была проинициализирована наследником
    }
protected:
    int     var_init;
private:
    int     var;
};
В принципе, поле можно сделать и не константным (как в примере выше), если это как то поможет проблеме ...
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 00:59
Цитата Сообщение от alkl Посмотреть сообщение
Мне необходимо, создавая наследника, проинициализировать переменную раньше, чем вызовется конструктор базового класса.
Может меня попровят сторожили, но это невозможно

Если рассуждать от обратного, то наследник, по вашей логике, инициализирует поле родителя. А если он этого не сделает? Она будет в подвешенном состоянии? Ну вот забыл родитель это сделать .... . После вызова конструтора родителя объект, что внутри родителя должен уже быть в полной боевой готовности!

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A
{
protected:
    int _q;
public:
    A()
    {
    }
};
 
class B : public A
{
protected:
    int _t;
public:
    B() : _t(_q) 
        // если тут _q в подвешенном состоянии был бы, то вообще беда бы была!!!!!
        // Но память под _q выделена и он проинициализирован A()
    {
    }
};
Еще пример, а если нету наследника? Получается создавая объект А у него поле "не инициализировано" ? Стандарт языка позаботился, что такого бы не было!
0
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 01:03  [ТС]
На этот случай в родителе дефолтное значение :
C++
1
2
3
4
5
6
7
8
9
10
class A{
public:
    A(){
        var=var_init;   // Тут нужно, чтобы 'var_init' уже была проинициализирована наследником
    }
protected:
    int     var_init;
private:
    int     var=0;      // Если наследника нет, то иним нулём
};
Добавлено через 1 минуту
Как раз, таки, мне это и нужно. Если в наследнике не указать значение, то оно будет неким по-умолчанию. Это один из моментов в моей задаче.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 01:12
Цитата Сообщение от alkl Посмотреть сообщение
int * * var=0; * * *// Если наследника нет, то иним нулём
Просто приймите за факт фразу далее: эта запись сахарок записи
C++
1
2
A() : var(0)
{}
Магии не бывает, класс А инициализирует свои переменные в списке инициализации - указаны они там явно или нет

Добавлено через 3 минуты
alkl, нельзя в списки инициализации наследника инициализировать поля родителя, потому что они уже проинициализированы - смотрите еще раз пример с MustBeInited()

Добавлено через 4 минуты
Еще довод:
http://en.cppreference.com/w/c... lizer_list
In the definition of a constructor of a class, member initializer list specifies the initializers for direct and virtual base subobjects and non-static data members.
где тут фраза and non-static subobjects data members ? Нету такой - потому, что это не верно
1
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 01:13  [ТС]
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
alkl, нельзя в списки инициализации наследника инициализировать поля родителя, потому что они уже проинициализированы
Странно, что компиль ругается на то, что поля не существует. Скорее, его просто ещё нет до создании экземпляра, и добавляется оно только когда он создаётся.

Будем дальше думать, спасибо...
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 01:15
Цитата Сообщение от alkl Посмотреть сообщение
Скорее, его просто ещё нет до создании экземпляра, и добавляется оно только когда он создаётся.
Да есть оно там! Я уже начинаю повторяться))))))) Он ругается, потому что думает что вы забыли создать в Б поле field, а уже стремитесь его проинитить - он же не может писать ошибку : Cannot init base class member - он не подозревает, что вы хотите невозможного
1
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 01:23  [ТС]
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
потому что думает что вы забыли создать в Б поле field, а уже стремитесь его проинитить
Ну и я о том. Он в этот момент его не видит и думает, что я забыл его добавить. А после его создания, уже видны все поля родителя, по этому я в его конструкторе спокойно могу обращаться к любому полю родителя.

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Я уже начинаю повторяться)))))))
Извините, не хотел заставлять Вас это делать

В общем, картина стала ясна. Будем кумекать, как лучше сделать ...
Хочется иметь некоторые переменные по-умолчанию, а при создании наследника, иметь возможность их изменять до вызова базового конструктора. Причём, хотелось бы это делать в виде списка инициализации.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 01:25
Цитата Сообщение от alkl Посмотреть сообщение
Он в этот момент его не видит
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A
{
protected:
    int _q;
public:
    A()
    {
    }
};
 
class B : public A
{
protected:
    int _t;
public:
    B() : _t(_q) 
        // если тут _q в подвешенном состоянии был бы, то вообще беда бы была!!!!!
        // Но память под _q выделена и он проинициализирован A()
    {
    }
};
тогда я маг и волшебник)) Видит он всё ... . А почему он не реагирует при _q(18) описал в посте после фразы Еще довод:. Он не верит своим двоичным сердцем, что вы настолько ошибаетесь, что пытаесь проинить то, что не можете - что можно проинить описано по ссылке http://en.cppreference.com/w/c... lizer_list


Цитата Сообщение от alkl Посмотреть сообщение
В общем, картина стала ясна.
1
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 01:35  [ТС]
Значит, по мнению компилятора, в случае
C++
1
    B() : _t(_q)
я не забыл добавить поле _q в 'B', а случае
C++
1
    B() : _q(_t)
забыл.
Картина ещё интереснее разворачивается
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 01:46
alkl, ага - почитайте ошибки

http://rextester.com/ITI45792 _q(18)
http://rextester.com/KAGWC31525 _t(_q)
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
14.03.2017, 01:46
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Просто приймите за факт фразу далее: эта запись сахарок записи
Говорят, что какая-то разница все-таки есть.
https://github.com/isocpp/CppC... rs-instead
1
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
14.03.2017, 01:50
ct0r,
The compiler-generated function can be more efficient.
Спорить с вами, или тем более с Страуструпом не буду - поверю, что дать возможность компилятору сварганить крутой default constr лучше.


Но моё мнение, полный бред. Особенно, при good practice мы упираемся рогами в Foo{"Hello", 12}
0
 Аватар для alkl
119 / 94 / 35
Регистрация: 18.12.2012
Сообщений: 654
14.03.2017, 01:56  [ТС]
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
http://rextester.com/KAGWC31525 _t(_q)
_q забыли просто вписать в класс 'A'. С ней нет никаких ошибок, и _q нормально видится в списке инициализации. Но только для чтения.
http://rextester.com/KXUTNA47635
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
14.03.2017, 01:58
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Особенно, при good practice мы упираемся рогами в Foo{"Hello", 12}
Это ты про что?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
14.03.2017, 01:58
Помогаю со студенческими работами здесь

Инициализация полей класса через vector<>
Здравствуйте, можете подсказать как правильно инициализировать поля класса, вот например есть класс MyClass, в нем 2 поля int x int у,...

Инициализация вещественных статических константных полей класса С++
static const double x=2.15; //c double и float не инициализирует. Почему??

Инициализация полей структуры в конструкторе по-умолчанию класса
Всем привет! #include &lt;string&gt; #include &lt;vector&gt; #pragma once class StudentsList { public:

Ошибка при наследовании класса
Всем доброго времени суток, пытаюсь отнаследовать класс, вот такой код я смастерил: #ifndef CLASS_H_ #define CLASS_H_ class stack ...

Ошибки при наследовании класса
Доброго времени суток!Возникли ошибки при компиляции кода Задание было такое:Создать абстрактный базовый класс Body (тело) с виртуальными...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru