С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.63/35: Рейтинг темы: голосов - 35, средняя оценка - 4.63
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712

Вызов конструктора базового класса

14.05.2019, 11:44. Показов 7989. Ответов 73
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую всех. Создаю класс-наследник std::string. У базового класса есть конструктор копии: std::string(const std::string& str). Правильно ли я создаю конструктор копии для своего класса?
C++
1
2
3
4
5
class IString : public std::string
{
 public:
 IString(const IString& String) : std::string(String) {}
};
Такой код работает, но смущает то, что я в конструктор копии класса std::string передаю объект типа IString.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.05.2019, 11:44
Ответы с готовыми решениями:

Вызов конструктора базового класса
Здравствуйте! Я вот начал изучать C# и немножечко освежил ООП. Но вот у меня вопрос. Я точно помню, что класс-наследник (конструкторы не...

Вызов конструктора базового класса из порожденного
Есть Базовый класс студент: имеет поля: фамилия, адрес, тел., возраст. Порожденный класс группа: имя группы, кол-во студентов в...

Вызов конструктора базового класса из класса-наследника
Можно ли вне списка инициализации вызвать конструктор базового класса ? class A { int a; public: A(int c):a(c){} ...

73
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
14.05.2019, 17:35
Лучший ответ Сообщение было отмечено TheCalligrapher как решение

Решение

Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Azazel-San Посмотреть сообщение
А в чем смысл в конце +100 добавлять?
Смысл в том, что класс-наследник может пользоваться совсем другим механизмом распределения памяти, несовместимым с механизмом по умолчанию. Вот это +100 и призвано "на коленке" смоделировать "другой механизм распределения памяти". Именно из-за этого +100 механизм по умолчанию "подавится" неправильным указателем.

Цитата Сообщение от Azazel-San Посмотреть сообщение
Потому что B::operator delete не будет вызван?
Да. Потому что вместо правильного B::operator delete вызван обычный ::operator delete.

В типичной реализации задача вызова правильного operator delete для объекта в динамической памяти тоже возложена на виртуальный деструктор.
3
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
14.05.2019, 17:37
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В типичной реализации задача вызова правильного operator delete для объекта в динамической памяти тоже возложена на виртуальный деструктор.
Спасибо, полезная инфа.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
14.05.2019, 17:48  [ТС]
Вот задал один вопрос, а столько полезного узнал! Теперь понятно, что наследоваться от класса, у которого нет виртуального деструктора, можно только в очень ограниченных случаях. Так как я планирую развивать создаваемый класс, то очевидно, что мне надо использовать композицию.
0
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
14.05.2019, 17:48
Цитата Сообщение от Croessmah Посмотреть сообщение
Нам важно лишь то, что адрес объекта не совпадает с адресом выделенной памяти.
Т.е. отчасти это попытка специально сделать что бы, обычный operator delete хрякнулся,
получив
Цитата Сообщение от Croessmah Посмотреть сообщение
неправильный указатель
?
Ну отсюда и ошибка
Code
1
invalid pointer: 0x0000000001449c84
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
14.05.2019, 17:53
Цитата Сообщение от Azazel-San Посмотреть сообщение
Т.е. отчасти это попытка специально сделать что бы, обычный operator delete хрякнулся,
получив
Именно так. То есть вместо +100 можно было вызвать какой-нибудь платформенный VirtualAlloc или sbrk, или выделить память в каком-то своем рукописном пуле (последнее как раз и моделируется этим +100).
0
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
14.05.2019, 17:55
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Именно так. То есть вместо +100 можно было вызвать какой-нибудь платформенный VirtualAlloc или sbrk, или выделить память в каком-то своем рукописном пуле (последнее как раз и моделируется этим +100).
Круто, спасибо.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12930 / 6798 / 1820
Регистрация: 18.10.2014
Сообщений: 17,205
14.05.2019, 18:58
Лучший ответ Сообщение было отмечено Croessmah как решение

Решение

Цитата Сообщение от d7d1cd Посмотреть сообщение
Теперь понятно, что наследоваться от класса, у которого нет виртуального деструктора, можно только в очень ограниченных случаях.
Это вы чересчур перегибаете. Это правило предназначено для первокурсников, для того, чтобы выработать у них правильные приоритеты и отбить привычку злоупотреблять наследованием. Но уже второкурсникам первым делом объясняют, что такого правила на самом деле нет. Современное С++ программирование активно использует наследование, не имеющее никакого отношения к виртуальным деструкторам.

CRTP не беспокоится ни о каких виртуальных деструкторах. std::enable_shared_from_this не беспокоится ни о каких виртуальных деструкторах. И т.д. и т.п.

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

Аргументы из разряда "а что, если кто-то сделает вот так" - это чушь. Если кто-то "сделает вот так" - сами виноваты будут.

Добавлено через 2 минуты
---

Вот здесь

Почему деструктор срабатывает больше раз, чем количество созданных объектов?

я уже описывал, как в реальности реализуется вызов правильного operator delete через посредство правильного деструктора.

Современные реализации GCC подчиняются требованиям Itanium ABI, согласно которым, вместо одного параметризованного деструктора у класса должно быть два отдельных деструктора (там их на самом деле даже три может быть). То есть современная реализация в GCC отличается в деталях, но суть остается та же.
7
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
14.05.2019, 22:12
Если плюсовый код не содержит UB - иди спать. Завтра с утра всё увидишь.
***

Уф-ф... Наконец-то всё прояснилось, а то уж начало казаться, что без виртуальных деструкторов - никуда. d7d1cd, соображения того плана, что delete на указателе базового класса (string) в вашем случае не сработает правильно, скорее всего вас не должны беспокоить. Поскольку вы не собираетесь использовать виртуальные методы, то вам и не предстоит создание коллекций полиморфных указателей. В этом случае беспокоиться не стоит. Если юзеру придёт в голову инициализировать указатель базового класса адресом наследника - это его проблема. Пусть кастит перед удалением или умрёт как мужчина. В конце концов в плюсах нет механизмов для запрета скастить любой указатель к void* а результат к чему то вовсе левому. А потом удалить. Хотя предусмотреть запрет на неявное преобразование указателя наследника к указателю базового класса в случае неполиморфного наследования можно было бы, наверное. Но не важно, важно, что чужая косорукость не ваша ответственность. А использование композиции защитит на уровне типа, но потребует много нудной писанины. Я бы предложил ещё вот какой вариант рассмотреть:
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
#include <iostream>
#include <string>
using namespace std;
template<class SelectedString >
struct IString;
 
template<>
struct IString<string>: public string
{
    IString()
        :string()
    {}
    template<class U>
     IString(const U& u)
         :string(u)
     {}
 
};
template<>
struct IString<wstring>: public wstring
{
    IString()
        :wstring()
    {}
    template<class U>
     IString(const U& u)
         :wstring(u)
     {}
 
};
 
 
struct IStringType
{
    typedef IString<string> SelectedStringStr;
    typedef IString<wstring> SelectedStringWStr;
};
 
int main()
{
IStringType::SelectedStringStr str("mama");
IStringType::SelectedStringWStr wstr(L"fat big mama");
cout<<str;
wcout<<wstr;
cin.get();
return 0;
}
Промежуточный уровень обобщения через шаблонный параметр может оказаться уместным.

Добавлено через 8 минут
Ну то есть, можно вообще обойтись без специализаций там где можно:
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
#include <iostream>
#include <string>
using namespace std;
template<class SelectedString >
struct IString:public SelectedString
{
    IString()
        :SelectedString()
    {}
    template<class U>
     IString(const U& u)
         :SelectedString(u)
     {}
};
 
struct IStringType
{
    typedef IString<string> SelectedStringStr;
    typedef IString<wstring> SelectedStringWStr;
};
 
int main()
{
IStringType::SelectedStringStr str("mama");
IStringType::SelectedStringWStr wstr(L"fat big mama");
cout<<str;
wcout<<wstr;
cin.get();
return 0;
}
И тут вдвое меньше писанины.
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
15.05.2019, 08:37  [ТС]
Вот так дааа! TheCalligrapher, спасибо большое за ликбез! И вправду говорят, что С++ был придуман для того, чтобы хорошими программистами не становились случайные люди (вроде меня). Преклоняюсь пред Вашими знаниями данного предмета!
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
15.05.2019, 09:15
d7d1cd, Если у базового класса нет виртуальных методов (а у std::string их нет, насколько мне известно), то крайне маловероятно что может понадобиться удаление через указатель на него, т.е. виртуальный деструктор. Идиотов, конечно хватает, но тратить время и силу на защиту от них в данном случае я бы не стал. Так что можешь смело вернуться к первоначальному варианту и не париться.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
15.05.2019, 09:47  [ТС]
Тут еще один нюанс вскрылся. При наследовании надо описать только конструкторы. Все остальные функции базового класса будут видны из моего класса. Вот только операторы не будут работать. То есть, операторы все равно надо прописывать в своем классе. Как правильно сказал n1b1ru, может мне все методы и не нужны будут, поэтому можно применять композицию и предоставлять доступ только к нужным функциям базового класса.
Блин, уже запутался и не знаю что применить... Может вообще с нуля написать свой класс строки?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
15.05.2019, 09:52
Цитата Сообщение от d7d1cd Посмотреть сообщение
Все, кроме операторов. То есть, операторы все равно надо прописывать в своем классе.
Операторы тоже наследуются, уже давно.

Добавлено через 1 минуту
Цитата Сообщение от d7d1cd Посмотреть сообщение
При наследовании надо описать только конструкторы.
Даже этого можно не делать. Делаешь using std::string::string; - в твоём случае

Добавлено через 53 секунды
Цитата Сообщение от d7d1cd Посмотреть сообщение
Как правильно сказал n1b1ru, может мне все методы и не нужны будут, поэтому можно применять композицию и предоставлять доступ только к нужным функциям базового класса.
А какие тебе будут не нужны?
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
15.05.2019, 10:09  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Операторы тоже наследуются, уже давно.
Тогда что я делаю не так в этом коде:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <string>
 
class IString : public std::string
{
 public:
 IString() : std::string() {}
 IString(const char* src) : std::string(src) {}
};
 
int main()
{
 IString str1, str2, str3;
 str1 = "Hello ";
 str2 = "World";
 str3 = str1 + str2; /* no match for 'operator=' (operand types are 'IString' and 'std::basic_string') */
    
 std::cout << str1 << std::endl;
 std::cout << str2 << std::endl;
 std::cout << str3 << std::endl;
 
 return 0;
}
Добавлено через 7 минут
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Даже этого можно не делать. Делаешь using std::string::string; - в твоём случае
Такое не прокатывает. Ошибка "std::string::string" is not declared.".
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
15.05.2019, 10:12
Цитата Сообщение от d7d1cd Посмотреть сообщение
Тогда что я делаю не так в этом коде:
Оператор + объявлен не в std::string, это внешний оператор, шаблонный https://en.cppreference.com/w/... perator%2B. Наверное, компилятор не может там преобразовать твой класс к std::basic_string<....>.
Попробуй сделать str1 += str2;
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
15.05.2019, 10:17
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
#include <iostream>
#include <string>
using namespace std;
template<class SelectedString >
struct IString:public SelectedString
{
    IString()
        :SelectedString()
    {}
    template<class U>
     IString(const U& u)
         :SelectedString(u)
     {}
};
 
struct IStringType
{
    typedef IString<string> SelectedStringStr;
    typedef IString<wstring> SelectedStringWStr;
};
 
int main()
{
IStringType::SelectedStringStr
        str1("mama"),
        str2("chto mi budem delat"),
        str3=str1+ ' ' +  str2;
cout<<str3+"?!";
 
cin.get();
return 0;
}
MinGW конечно компилирует и работает. Но MVS2008(!) тоже.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
15.05.2019, 10:27
Цитата Сообщение от d7d1cd Посмотреть сообщение
Такое не прокатывает. Ошибка "std::string::string" is not declared.".
C++
1
2
3
4
5
6
7
8
9
10
11
12
class IString : public std::string
{
public:
    using std::string::string;
    IString() : std::string() {}
    IString(const char* src) : std::string(src) {}
};
 
static IString s(10, '!');
 
................
std::cout << s << std::endl;
Какая у тебя студия? У меня - 2017

Добавлено через 1 минуту
Кстати, тоже работает

C++
1
2
3
        static IString s2(10, 'X');
        auto s3 = s2 + s;
        std::cout << s << ", " << s3<< std::endl;
Добавлено через 2 минуты
А вот так IString s3 = s2 + s; нет

Добавлено через 28 секунд
error C2440: 'initializing': cannot convert from 'std::basic_string<char,std::char_traits <char>,std::allocator<char>>' to 'IString'

Добавлено через 4 минуты
Похоже, надо явно определять IString(std::string &&s) : std::string(std::move(s)) {}
0
Mental handicap
 Аватар для Azazel-San
1246 / 624 / 171
Регистрация: 24.11.2015
Сообщений: 2,429
15.05.2019, 11:05
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
А вот так IString s3 = s2 + s; нет
Конечо для вы хотите что бы получился IString, надо определять свои операторы.
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Похоже, надо явно определять IString(std::string &&s) : std::string(std::move(s)) {}
Ну, вы же в своем примере определили явно конструкторы, а мув конструктор теперь компилятор за вас не сгенерит.
C++
1
2
3
4
5
6
7
8
struct mstring : public std::string {
    using std::string::string;
};
 
int main() {
    mstring a("Hello");
    mstring c(std::move(a)); // call mstring(mstring&&)
}
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
15.05.2019, 11:13
Цитата Сообщение от Azazel-San Посмотреть сообщение
Конечо для вы хотите что бы получился IString, надо определять свои операторы.
Ну, не оператор + точно. Только конструкторы и операторы преобразования.

Добавлено через 1 минуту
Цитата Сообщение от Azazel-San Посмотреть сообщение
Ну, вы же в своем примере определили явно конструкторы, а мув конструктор теперь компилятор за вас не сгенерит.
Мог бы использовать соответствующий коструктор std::string

Добавлено через 36 секунд
Тем более, это не move-конструктор
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
15.05.2019, 11:37  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Какая у тебя студия? У меня - 2017
У меня система IBM i. Там компилятор основанный на IBM XL C/C++ for AIX.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
15.05.2019, 11:57
Цитата Сообщение от d7d1cd Посмотреть сообщение
У меня система IBM i. Там компилятор основанный на IBM XL C/C++ for AIX.
Похоже, он 17-й стандарт не поддерживает. Тогда понятно, кода будет побольше.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.05.2019, 11:57
Помогаю со студенческими работами здесь

Знакомство с наследованием. Вызов конструктора базового класса
В инете немного почиатл про наследование и решил сразу перейти к практике Есть два класа point и apoint вот хидер #ifndef...

Вызов базового конструктора
Такая вот ситуация. Думаю, проблема в объявлении и инициализации массива m. Я бы инициализировал уже в конструкторе, но сначала вызовет...

Вызвать конструктор производного класса без конструктора базового класса
Здравствуйте! У меня есть базовый класс треугольник и производный класс равносторонний треугольник.В конструкторе треугольника вводятся...

Наследование конструктора из базового класса
#include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;cstring&gt; using namespace std; //////////////////// class String { ...

Инициализация конструктора базового класса
class animal { public: animal(int a):ianimal(a){} protected: int ianimal; }; class bird:public animal


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути
Programma_Boinc 01.01.2026
Учёным и волонтёрам проекта «Einstein@home» удалось обнаружить четыре гамма-лучевых пульсара в джете Млечного Пути Сочетание глобально распределённой вычислительной мощности и инновационных. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
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. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru