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

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

14.05.2019, 11:44. Показов 8976. Ответов 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
13229 / 6861 / 1827
Регистрация: 18.10.2014
Сообщений: 17,393
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
13229 / 6861 / 1827
Регистрация: 18.10.2014
Сообщений: 17,393
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
13229 / 6861 / 1827
Регистрация: 18.10.2014
Сообщений: 17,393
14.05.2019, 18:58
Лучший ответ Сообщение было отмечено Croessmah как решение

Решение

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

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

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

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

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

Вот здесь

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

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

Современные реализации GCC подчиняются требованиям Itanium ABI, согласно которым, вместо одного параметризованного деструктора у класса должно быть два отдельных деструктора (там их на самом деле даже три может быть). То есть современная реализация в GCC отличается в деталях, но суть остается та же.
7
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 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
9007 / 4708 / 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
Ответ Создать тему
Новые блоги и статьи
Nekobox - outbounds[0].transport: unknown transport type: raw
damix 01.10.2026
Фикс ошибки Правым кликом по серверу -> отладочная информация -> edit Заменить "net": "raw", на "net": "tcp", Нажать кнопку reload.
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru