Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.60/15: Рейтинг темы: голосов - 15, средняя оценка - 4.60
9 / 9 / 0
Регистрация: 22.01.2012
Сообщений: 59

Почему не наследуются конструкторы?

17.02.2015, 15:37. Показов 3267. Ответов 30
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Гугл говорит, что конструкторы в C++ унаследовать никак нельзя. Почему так? В чём проблема с их наследованием?
Хотел написать вектор, у которого operator [] переопределён на at()
C++
1
2
3
4
5
6
template <class T>
struct svector : private vector <T> {
    T & operator [] (int n) {
        return this -> at (n);
    }
};
Но так теряются конструкторы. Спасает вот такой костыль:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <class T>
struct svector : private vector <T> {
    T & operator [] (int n) {
        return this -> at (n);
    }
 
    svector () : vector <T> () {}
 
    template <class T1>
    svector (const T1 &a) : vector <T> (a) {}
 
    template <class T1, class T2>
    svector (const T1 &a, const T2 &b) : vector <T> (a, b) {}
};
Но это уже костыль. Так что не тру)
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
17.02.2015, 15:37
Ответы с готовыми решениями:

Наследуются ли конструкторы?
Привет. Хочу спросить, если базовый класс имеет открытый конструктор по умолчанию, то при открытом наследовании будет ли создан...

Наследуются ли конструкторы и деструкторы?
При наследовании происходит ли наследование конструкторов и деструкторов базового класса?

Почему не наследуются переменные ?
Здравствуйте, столкнулся с такой проблемой в классах наследниках не наследуются переменные родителя. В чем ошибка? Заранее спасибо. ...

30
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
17.02.2015, 15:45
Цитата Сообщение от Андрей Xomach Посмотреть сообщение
Спасает вот такой костыль
C++
1
2
3
4
5
6
template <typename T>
struct svector : public std::vector<T>
{
   template<typename ... Args>
   svector(Args... args) : std::vector<T>(args...) {}
};
2
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
17.02.2015, 15:45
C++
1
2
3
4
5
6
7
8
9
10
11
12
template <class T>
struct svector : private vector <T> {
 
    typedef vector <T>
        parent;
 
    using parent::parent;
 
    T & operator [] (int n) {
        return this -> at (n);
    }
};
1
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
17.02.2015, 15:48
Цитата Сообщение от Андрей Xomach Посмотреть сообщение
Почему так?
А как Вы себе это представляете?
Ну вот есть в наследнике конструктор с определенным параметром и в базовом есть - конфликт.
Не хочу я наследовать конструкторы(чаще так и бывает), тогда нужно все конструкторы базового класса прятать куда-то, тоже не тру.
А при множественном наследовании как быть? А с конструктором копий?
0
9 / 9 / 0
Регистрация: 22.01.2012
Сообщений: 59
17.02.2015, 15:51  [ТС]
Croessmah, Как и с обычными методами. Если два одинаковых конструктора, в приорете тот, который у наследника.
При множественном наследовании проблем не вижу.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
17.02.2015, 15:58
Цитата Сообщение от Croessmah Посмотреть сообщение
А как Вы себе это представляете?
Вот так я это себе представляю:

http://rextester.com/NUNQFZ68981

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
//Title of this code
//Compiler Version 18.00.21005.1 for x86
 
#include <iostream>
#include <vector>
#include <stdexcept>
 
template<class T>
struct svector : private ::std::vector<T>
{
    typedef ::std::vector<T>
        parent;
 
    using parent::parent;
 
    T& operator[](const size_t n)
    {
        return this->at(n);
    }
    const T& operator[](const size_t n)const
    {
        return this->at(n);
    }
   
};
 
int main()
{
    std::cout << "Hello, world!\n";
    
    const int ar[]={1,2,3};
    svector<int> example(ar, ar+3);
    
    try{
        example[10];
    }
    catch(const std::out_of_range& e)
    {
        std::cout<<"OUT OF RANGE: " << e.what()<<'\n';
    }
    
    catch(const std::exception& e)
    {
        std::cout<<e.what()<<'\n';
    }
    
    
}
1
9 / 9 / 0
Регистрация: 22.01.2012
Сообщений: 59
17.02.2015, 15:59  [ТС]
Croessmah, ваш код у меня не компилируется
(mingw-32, -std=C++11)
C++
1
error: 'using svector<T>::parent::parent' conflicts with a previous declaration
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
17.02.2015, 16:01
Цитата Сообщение от Андрей Xomach Посмотреть сообщение
private vector <T>
Если наследник собственных полей не добавляет, то для того,
что б слегка поменять логику отдельного метода наследоваться приватно не обязательно.


И что б вы знали: для передачи количества или индексов массивов используют беззнаковый size_t.
1
9 / 9 / 0
Регистрация: 22.01.2012
Сообщений: 59
17.02.2015, 16:38  [ТС]
Цитата Сообщение от Croessmah Посмотреть сообщение
А как Вы себе это представляете?
Странно видеть от вас такой вопрос, когда вы сами предложили полноценное (как мне кажется) решение

Добавлено через 1 минуту
hoggy, И всё-таки на mingw не компилируется. Как у меня, так и в онлайн-компиляторе (http://www.onlinecompiler.net/)

Добавлено через 15 минут
hoggy, а ещё я вовсе не понимаю, что это за строчка такая
Цитата Сообщение от hoggy Посмотреть сообщение
C++
1
using parent::parent;
0
Эксперт С++
4986 / 3093 / 456
Регистрация: 10.11.2010
Сообщений: 11,170
Записей в блоге: 10
17.02.2015, 16:53
Цитата Сообщение от Андрей Xomach Посмотреть сообщение
а ещё я вовсе не понимаю, что это за строчка такая
В C++11 это называется наследование конструкторов (inheriting constructors).
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
17.02.2015, 17:34
Лучший ответ Сообщение было отмечено Андрей Xomach как решение

Решение

Цитата Сообщение от Андрей Xomach Посмотреть сообщение
И всё-таки на mingw не компилируется. Как у меня, так и в онлайн-компиляторе (http://www.onlinecompiler.net/)
1. Могу порекомендовать вам,
а так же онлайн сервису на который вы ссылаетесь, обновить компилятор.

свежий компилятор gcc, который идет в коробке mingw поддерживает с++11
http://ideone.com/DMBDmm

------------------------------------------------------------------------

2. Либо использовать более "старую" технику основанную на variardic template.

Например, так это можно реализовать для компилятора cl (вижуал студия),
который плохо поддерживает с++11

http://rextester.com/MNLCQ86757

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
//Title of this code
//Compiler Version 18.00.21005.1 for x86
 
#include <iostream>
#include <utility>
#include <vector>
#include <stdexcept>
 
template<class T>
struct svector : private ::std::vector<T>
{
    typedef ::std::vector<T>
        parent;
 
    template<typename ... Args>
    svector(Args&&... args) 
        : parent( std::forward<Args>(args)... ) 
    {}
 
    T& operator[](const size_t n)
    {
        return this->at(n);
    }
    const T& operator[](const size_t n)const
    {
        return this->at(n);
    }
   
};
 
int main()
{
    std::cout << "Hello, world!\n";
    
    const int ar[]={1,2,3};
    svector<int> example(ar, ar+3);
    
    try{
        example[10];
    }
    catch(const std::out_of_range& e)
    {
        std::cout<<"OUT OF RANGE: " << e.what()<<'\n';
    }
    
    catch(const std::exception& e)
    {
        std::cout<<e.what()<<'\n';
    }
}
Особенное внимание обратите на конструкцию конструктора:

C++
1
2
3
4
    template<typename ... Args>
    svector(Args&&... args)                //<--- универсальная ссылка
        : parent( std::forward<Args>(args)... )  //<--- аргументы передаются, как форварды
    {}
Универсальные ссылки нужны, для оптимизации передачи аргументов:

-- избежать копирования аргументов
-- аргументы могут быть как lvalue, так и rvalue

std::forward нужен, для оптимизации запуска конструктора.
Благодаря ему становится возможным запуск move-конструктора

------------------------------------------------------------------------

3. Если ваш компилятор слишком стар и вообще не поддерживает с++11,
то можно реализовать это так, как это делалось в рамках с++03:

C++
1
2
3
4
5
6
7
8
9
    template<class A1>
    svector(A1& a1) 
        : parent(a1) 
    {}
    
    template<class A1, class A2>
    svector(A1& a1, A2& a2) 
        : parent(a1,a2) 
    {}
И пошла копипаста под все возможное количество параметров.

В рамках с++03 стратегия оптимальной передачи аргументов - предмет особых плясков с бубнами.

В данном сообщении я этот нюанс рассматривать не буду,
поскольку полагаю с++03 в 2015 году не очень актуален.

Добавлено через 15 минут
Цитата Сообщение от Андрей Xomach Посмотреть сообщение
а ещё я вовсе не понимаю, что это за строчка такая
using parent::parent;

Ключевое слово using сообщает компилятору, что указанная сущность должна быть видима в текущем пространстве имен.

В контексте классов, это позволяет контролировать модификаторы доступа к унаследованному функционалу.

Пример:

http://rextester.com/TEKK89627


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
//Title of this code
//Compiler Version 18.00.21005.1 for x86
 
#include <iostream>
using namespace std;
 
struct base
{
    void foo()const { cout<<"base::foo\n"; }
    void bar()const { cout<<"base::bar\n"; }
};
 
 
struct der1: private base 
{
    // теперь снаружи доступен метод базового класса
    using base::foo;  
    
protected:
 
    // теперь метод доступен всем потомкам
    using base::bar;  
    
};
 
struct der2: base 
{
    //мы унаследовались публично, но хотим сделать некоторые методы недоступными снаружи
    //просто объявим их в закрытой секции:    
    
    void work()const { this->bar(); };
    
private:
    
    // теперь метод доступен только изнутри класса
    using base::bar;  
    
    
    
    
};
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    der1().foo(); //<--- работает, потому что объявлен в публичной области видимости
    
    der2().work(); 
    
}
Все что требуется от программиста:

Что бы открыть доступ: просто перечислить методы базового класса в публичной зоне.
Что бы закрыть доступ: просто перечислить методы базового класса в частной зоне.
Что бы защитить доступ: просто перечислить методы базового класса в защищенной зоне.
1
9 / 9 / 0
Регистрация: 22.01.2012
Сообщений: 59
17.02.2015, 17:59  [ТС]
hoggy, огромное вам спасибо, вспомнил и узнал много нового.
Вот только в реализации для C++03 не лучше бы использовать const A1 & чтобы аргумент мог быть rvalue?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
17.02.2015, 18:16
Цитата Сообщение от Андрей Xomach Посмотреть сообщение
для C++03 не лучше бы использовать const A1 & чтобы аргумент мог быть rvalue?
Это не будет работать для функций, которые ожидают ссылки на изменяемые объекты.

Проблема оптимальной стратегии передачи аргументов в с++03 это "легаси-косяк-в-дизайне-языка".

Рассмотрим пример:

http://rextester.com/KMOTF77045

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
//Title of this code
//Compiler Version 18.00.21005.1 for x86
 
#include <iostream>
 
// хочет ссылку, по которой можно изменить оригинальный объект
struct foo
{
    foo(int& val){}
};
 
// хочет ссылку, по которой изменить оригинальный объект нельзя
struct bar
{
    bar(const int& val){}
};
 
 
template<class T>
struct der: T
{
    template<class U>
    der(U& v)
        : T(v) 
    {}
    
};
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    int v1 = 10;
    
    const int v2 = 10;
    
    der<foo> f(v1);
    der<bar> b(v2);
}
Мы наблюдаем успешную компиляцию.


Для константного аргумента шаблон раскроется в const T&
А для не константного аргумента раскроется в T&

Поэтому, это будет работать в обоих случаях.

Но есть проблема:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// хочет ссылку, по которой изменить оригинальный объект нельзя
struct bar
{
    bar(const int& val){}
};
 
 
template<class T>
struct der: T
{
    template<class U>
    der(U& v)
        : T(v) 
    {}
    
};
 
int main()
{
    der<bar> b(100); //<--- ошибка
 // error C2664: 'der<bar>::der(const der<bar> &)' : cannot convert argument 1 from 'int' to 'int &'
 
}
"легаси-косяк-в-дизайне-языка" заключается в том,
что компилятор считает, что литерные числовые константы имеют тип данных, который не является const

Циферку 100 он попытался передать через T&, а не через const T&

На самом деле, циферка 100 - это rvalue, которое само по себе не является const.

Однако, поскольку в рамках с++03 пользователи не могут работать с rvalue явным образом,
то попытка сделать универсально превращается в аццкие пляски с бубнами.
Любое решение оказывается не тривиальным.

В простейшем случае (когда всего 1 аргумент) достаточно посадить рядышком ещё один конструктор,
у которого аргумент явный const T&

Но если аргументов может быть много, и некоторые из них должны раскрываться, как T&, а другие - как const T&,
то начинается увлекательное путешествие в мир граблей языка с++
1
28 / 28 / 5
Регистрация: 23.04.2014
Сообщений: 130
17.02.2015, 23:31
Конструктор предка и так содержится в в наследнике, при вызове конструктора наследника по цепочке вызываются все конструкторы предков. Поэтому нет смысла его копировать.
Например, есть класс
C++
1
2
3
4
5
6
7
struct parent
{
    parent(type_a a, type_b b) : a(a), b(b)
    {
        //some code
    }
};
и есть класс
C++
1
2
3
4
5
6
7
8
struct child : parent
{
    child(type_a a, type_b b, type_c c) : parent(a, b), c(c)
    {
        //some code
    }
};
}
То же самое и с деструктором, при его вызове по цепочке вызывают все деструкторы предков. Поэтому деструктор всегда должен иметь определение, даже если он чисто виртуальный

Добавлено через 6 минут
Не успел откорректировать сообщение)

В этом коде видно, что можно вызывать явно конструктор предка. Т.е. сначала вызывается конструктор наследника, затем конструктор предка, и так далее по цепочке.

С деструктором та же ситуация, при его вызове по той же самой цепочке, но в обратном порядке вызываются все деструкторы предков. Поэтому деструктор всегда должен иметь определение, даже если он чисто виртуальный
0
654 / 575 / 164
Регистрация: 13.12.2012
Сообщений: 2,124
18.02.2015, 10:53
Цитата Сообщение от GREGOR_812 Посмотреть сообщение
Т.е. сначала вызывается конструктор наследника, затем конструктор предка, и так далее по цепочке.
ну сначала так то, вызовется конструктор самого первого родителя
0
Неэпический
 Аватар для Croessmah
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,035
Записей в блоге: 1
18.02.2015, 12:17
Цитата Сообщение от aLarman Посмотреть сообщение
ну сначала так то, вызовется конструктор самого первого родителя
Сначала вызываются конструкторы дочерних. Это уже они вызывают конструкторы предков.
Цитата Сообщение от hoggy Посмотреть сообщение
Вот так я это себе представляю
ну тут же Вы указываете явно что использовать с помощью using-declaration. По умолчанию они не наследуются. А я именно к положению "по-умолчанию", но всё равно спасибо за замечание. Я уже забыл об этом.
0
18.02.2015, 13:03

Не по теме:

Croessmah, да я скорее про последовательность, да естественно в начале вызывается конструктор наследника(мы же наследника создаем), но завершается создание объекта конструктором наследника(точнее инициализацией его полей), а конструкторы базовых вызываются с головы

0
28 / 28 / 5
Регистрация: 23.04.2014
Сообщений: 130
18.02.2015, 14:20
Цитата Сообщение от aLarman Посмотреть сообщение
завершается создание объекта конструктором наследника(точнее инициализацией его полей)
Инициализация полей может происходить до исполнения конструктора
0
18.02.2015, 14:33

Не по теме:

Цитата Сообщение от GREGOR_812 Посмотреть сообщение
Инициализация полей может происходить до исполнения конструктора
Интересно было бы посмотреть на пример :)

0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
18.02.2015, 15:19
Цитата Сообщение от DrOffset Посмотреть сообщение
Интересно было бы посмотреть на пример
Вероятно речь об этом:
C++
1
2
3
4
5
struct C
{
   C() { /* здесь i уже проинициализировано */ }
   int i = 42;
};
Хотя аналогичное достигается и в до С++11 версиях через инициализатор конструктора. Который тоже выполняется до тела конструктора.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
18.02.2015, 15:19
Помогаю со студенческими работами здесь

Конструкторы. Почему-то по умолчанию и копирующий не срабатывают, помогите найти ошибку.
Написал небольшой код, для понимания, как работают различные варианты конструкторов (т.е. по умолчанию, с параметром и копирующий), но...

Почему наследуются свойства применяемые в таблице
Здравствуйте! Есть две страницы на каждой находится таблица. Я прописала свойства для первой таблицы, где мне нужно, чтобы border...

Почему в описании языка "интерфейсы наследуются"?
Источник, цитата: Интерфейсы реализуются, а не наследуются...

Webpack собирает проект, а приложение говорит что мои конструкторы не конструкторы
Помогите пожалуйста, в едином файле (не билде) всё работает хорошо, как только начинаю отделять классы и создавать билд, сразу ошибка в...

Не наследуются стили
Оформляю меню нестандартными шрифтами. Возникла следующая проблема: категории и подкатегории никак не хотят оформляться разными шрифтами. ...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru