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

Условия для конструктора с параметрами

22.04.2021, 02:35. Показов 4771. Ответов 17
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте. Я определила конструктор объекта Group в файле .cpp:

C++
1
2
3
4
5
6
//конструктор объекта
Group::Group(int member)
{
    size = member;
    p = new Ship[size];  //Создание объекта через указатель и динамический массив
}
Далее в файле main.cpp с помощью цикла for заполним массив данными. Для этого в теле цикла создадим объект Ship, проинициализировав все его данные, и с помощью функции PutShip занесем объект в массив:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int i;
 
    string n_val[5] = { "Бисмарк", "Аврора", "Титаник", "Черная жемчужина", "Санта-Мария" }; //наименование
    int displacement_[5] = { 50900, 7130, 52310, 7000, 200 };//водоизмещение 
    string t_val[5] = { "корабль", "крейсер", "лайнер", "фрегат", "Каракка" };//тип
 
    Group group(5);  //создаем объект типа Group размером 5 записей
 
 
    //заполняем массив данными
    for (i = 0; i < 5; i++) 
    {
        Ship ves(n_val[i], displacement_[i], t_val[i]);
        group.PutShip(i, ves);
    }
 
    }
Преподаватель указал на ошибку:В конструктор с параметрами для группы допускается сейчас передавать отрицательное или нулевое количество элементов.
Но я указала условие при заполнении массива данными. Можно ли добавить какое-то услове в сам конструктор?

Еще преподавательпишет, что нет проверки в функции добавления элементов в группу, можно передать любой номер.
Если я добавлю условие через assert, это будет корректоно?

C++
1
2
3
4
5
6
//функция заносит объект ves типа Ship в i-ое место массива
void Group::PutShip(int i, Ship& ves) 
{
    assert(i >= 0 && i < 5);
    p[i] = ves;
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.04.2021, 02:35
Ответы с готовыми решениями:

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

Из конструктора без параметров в конструктор с параметрами
Подскажите, пожалуйста, как в классах из конструктора без параметров сделать конструктор с...

Ошибка при вызове конструктора с параметрами
подскажите, почему при вызове конструктора с параметрами выдает ошибку сегментации ...

Вызов базового конструктора с параметрами из дочернего класса
Всем привет. Есть базовый класс, у которого есть конструктор с параметром. Создал дочерний класс...

17
Мозгоправ
1744 / 1038 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
22.04.2021, 03:27 2
Ann1984, Group - это аналог std::vector?

Цитата Сообщение от Ann1984 Посмотреть сообщение
Преподаватель указал на ошибку:В конструктор с параметрами для группы допускается сейчас передавать отрицательное или нулевое количество элементов. <...> Можно ли добавить какое-то услове в сам конструктор?
Нужно.

В конструкторе параметр размера и, соответственно, член класса size, можно сделать типа size_t, который беззнаковый. Тем более, что вы его применяете в операторе new[], который принимает как раз size_t.

Либо, если уж так необходимо именно int, можно на невалидный параметр либо выбрасывать исключение (до выделения памяти), либо, при отрицательном параметре, обнулять член size. Тогда, с учётом контроля индекса при обращении к экземпляру класса (см. ниже), с этим экземпляром не получится ничего сделать. Да, будут ошибочные ситуации, которые в любом случае придётся обрабатывать, но программа не будет крашиться или выдавать бессмысленные результаты.

Цитата Сообщение от Ann1984 Посмотреть сообщение
Еще преподаватель пишет, что нет проверки в функции добавления элементов в группу, можно передать любой номер.
Правильно пишет. Надо добавить проверку.

Цитата Сообщение от Ann1984 Посмотреть сообщение
Если я добавлю условие через assert, это будет корректоно?
Нет.
assert() работает только для конфигурации Debug. В релизной конфигурации этот вызов будет выпилен.

Надо добавлять нормальную проверку значения индекса на выход за пределы массива. Тут возникает вопрос: а что делать, если индекс не прошёл проверку? Вариантов несколько:

1. Сделать вид, что ничего не произошло. Т.е. просто выйти из метода. Категорически не рекомендуется.

2. Выдать диагностическое сообщение в cerr и выйти из метода. Тоже не рекомендуется. Можно использовать на этапе отладки, но не далее. Да и не всегда cerr доступен.

3. Вернуть из метода признак ошибки. Например:
C++
1
2
3
4
5
6
7
bool Group::PutShip(size_t index, const Ship& ves) 
{
    if (index >= size)
        return false;
    p[index] = ves;
    return true;
}
В этом варианте при вызове метода надо не забывать проверять, что вернул метод.

4. Выкинуть исключение. При этом надо решить какого вида будет исключение. Обычно используются либо стандартные классы исключений из <stdexcept>, либо класс exception из <exception>, либо свой класс исключения, унаследованный от exception, либо чисто свой класс исключения. Например:
C++
1
2
3
4
5
6
7
8
#include <stdexcept>
// ...
void Group::PutShip(size_t index, const Ship& ves) 
{
    if (index >= size)
        throw range_error("Group::PutShip");
    p[index] = ves;
}
В этом варианте в вызывающем коде нужно ловить исключения посредством try/catch.
2
0 / 0 / 0
Регистрация: 09.10.2018
Сообщений: 87
22.04.2021, 04:10  [ТС] 3
L0M , спасибо за подсказки. Если я в конструкторе пропишу тип size_t , то это поможет избежать отриц.значений. Но как исключить нулевые? Ведь просто так прописывать нельзя?

C++
1
2
3
4
5
6
Group::Group(size_t member)// используем беззнаковый целочисленный тип size_t
{
    size = member;
    size != 0;
    p = new Ship[size];  //Создание объекта через указатель и динамический массив
}
Добавлено через 3 минуты
Еще преподаватель указал, что в перегруженный оператор [ ] можно передать некорректный индекс, и это не проверяется. Я добавила проверку через assert, гугл подсказал. Но получается что его нельзя так использовать. Или тут это допустимо?

C++
1
2
3
4
5
6
//перегрузка оператора индкексирования
Ship& Group::operator[](size_t i)  
{
    assert(i >= 0 && i < 5);//  проверяем, чтобы выражение было внутри диапазона(т.к у нас 5 кораблей), иначе сообщение об ошибке
    return p[i];
};
0
Мозгоправ
1744 / 1038 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
22.04.2021, 04:54 4
Цитата Сообщение от Ann1984 Посмотреть сообщение
Если я в конструкторе пропишу тип size_t , то это поможет избежать отриц.значений. Но как исключить нулевые?
Не нужно исключать нулевое значение. Я вам в предыдущем сообщении написал
Цитата Сообщение от L0M Посмотреть сообщение
<...> обнулять член size. Тогда, с учётом контроля индекса при обращении к экземпляру класса (см. ниже), с этим экземпляром не получится ничего сделать. Да, будут ошибочные ситуации, которые в любом случае придётся обрабатывать, но программа не будет крашиться или выдавать бессмысленные результаты.
new Ship[0] - вполне законная конструкция. И в деструкторе такой блок памяти нулевого размера
нужно освобождать также, как и обычный.

Строка 4 в первом фрагменте бессмысленна.

Цитата Сообщение от Ann1984 Посмотреть сообщение
Еще преподаватель указал, что в перегруженный оператор [ ] <...>
С operator [] ситуация аналогична методу PutShip() с тем отличием, что вернуть признак ошибки невозможно. Т.е. вариант 3 исключается. Наилучшее решение - бросить исключение.

Для std::vector::operator[] в случае невалидного индекса написано, что результат неопределён. Т.е. классический случай UB. В реальности в std::vector::operator[] компилятор Visual Studio 2019 16.9.4 тупо не проверяет индекс на выход за границу массива (в отличие от метода std::vector::at(), который в случае невалидного индекса выбрасывает исключение). При этом в лучшем случае портится куча, а в худшем будет обращение к памяти, не принадлежащей куче. В обоих случаях прилетит исключение, но только уже от системы, вопрос только в том, когда это произойдёт (и как долго придётся потом искать где ошибка).

Цитата Сообщение от Ann1984 Посмотреть сообщение
Я добавила проверку через assert, гугл подсказал.
Подсказками Гугла надо с умом пользоваться

Ещё раз: assert() только для отладочной конфигурации. Этот макрос предназначен для отладки. В релизной конфигурации он не работает.
1
0 / 0 / 0
Регистрация: 09.10.2018
Сообщений: 87
23.04.2021, 12:55  [ТС] 5
L0M, я тут попробовала написать обработчик исключений. Похоже на правду?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Group::PutShip(size_t i, const Ship& ves) 
{
    try // ищем исключения внутри этого блока и отправляем их в соответствующий обработчик catch
    {
        if (i >= size) // Если пользователь ввел некорректное число, то выбрасывается исключение
            throw range_error("Group::PutShip"); // выбрасывается исключение 
        // Если пользователь ввел корректное число, то выполняется операция 
        p[i] = ves;
    }
    catch (const exception &ex)//обработчик исключений 
    {
        cerr << "Ошибка: " << ex.what() << '\n';
    }
    
}
0
Мозгоправ
1744 / 1038 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
23.04.2021, 13:54 6
Цитата Сообщение от Ann1984 Посмотреть сообщение
обработчик исключений. Похоже на правду?
Похоже, но отдалённо.

Исключение у вас выбрасывается в методах класса. А ловить вы его должны в вызывающем коде.
1
18901 / 9859 / 2410
Регистрация: 30.01.2014
Сообщений: 17,302
23.04.2021, 16:58 7
Цитата Сообщение от L0M Посмотреть сообщение
Ещё раз: assert() только для отладочной конфигурации. Этот макрос предназначен для отладки. В релизной конфигурации он не работает.
Тут по условию задачи, честно говоря ,не понятно однозначно, что такой вариант не подходит.

Цитата Сообщение от Ann1984 Посмотреть сообщение
Но получается что его нельзя так использовать.
Конечно можно. Тут все зависит от того, что именно вы вкладываете в понятие "некорректный индекс". Если некорректный индекс - это логическое состояние вашей программы, то да, нужно исключение. Если некорректный индекс в вашей программе невозможен в принципе, то нужен ассерт.

Для примера с std::vector реализованы сразу обе стратегии:
1) Отладочная версия operator[] бросается ассертами, потому что operator[] предполагается к использования в контекстах, где некорректный индекс невозможен в принципе, например в пределах цикла, который ограничивает индексацию своим условием в корректных пределах. Ассерт определяет инвариант, который мы проверяем при разработке, а когда программа отлажена, со спокойной совестью выкидываем проверку, чтобы не тратить на нее время: мы же уже удостоверились на этапе отладки\тестирования что у нас нигде в программе не допускаются некорректные состояния.
2) Функция at() бросается исключением, потому что она предполагается к использования в случаях, когда неправильный индекс является частью логики вашей программы. Например, если его вводит пользователь (он может ошибиться) или он читается из файла (файл может быть неправильным). Тут стоит отметить, что второй случай всегда можно реализовать с помощью первого, просто перенеся проверку логического состояния на уровень выше, таким образом, чтобы исключить срабатывание ассерта, но это уже второй вопрос.
1
Мозгоправ
1744 / 1038 / 468
Регистрация: 01.10.2018
Сообщений: 2,138
Записей в блоге: 2
23.04.2021, 17:07 8
Цитата Сообщение от DrOffset Посмотреть сообщение
Тут по условию задачи, честно говоря ,не понятно однозначно, что такой вариант не подходит.
ТС написала, что "преподаватель указал, что в перегруженный оператор [ ] можно передать некорректный индекс". Видимо всё-таки предполагается, что в релизе некорректный индекс может быть. Поэтому я предложил кидать исключение.

Цитата Сообщение от DrOffset Посмотреть сообщение
Отладочная версия operator[] бросается ассертами
А вот не бросается. По крайней мере в Visual Studio 2019 16.9.4. Специально проверял, перед тем как написать об этом в #4.
1
18901 / 9859 / 2410
Регистрация: 30.01.2014
Сообщений: 17,302
23.04.2021, 18:19 9
Цитата Сообщение от L0M Посмотреть сообщение
А вот не бросается.
Бросается.
Это настраивается.
Не помню точно как это сделать из интерфейса студии, но в конечном счете должен быть определен макрос _ITERATOR_DEBUG_LEVEL=1

Добавлено через 3 минуты
Цитата Сообщение от L0M Посмотреть сообщение
Видимо всё-таки предполагается, что в релизе некорректный индекс может быть. Поэтому я предложил кидать исключение.
И все-таки на всякий случай лучше не быть столь категоричным. А то у ТС может сложиться неверное понимание общей картины.
1
0 / 0 / 0
Регистрация: 09.10.2018
Сообщений: 87
24.04.2021, 07:05  [ТС] 10
L0M,
у меня есть файл group.cpp. Там описана данная функция:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//функция заносит объект ves типа Ship в i-ое место массива
void Group::PutShip(size_t i, const Ship& ves) 
{
    try // ищем исключения внутри этого блока и отправляем их в соответствующий обработчик catch
    {
        if (i >= size) // Если пользователь ввел некорректное число, то выбрасывается исключение
            throw range_error("Group::PutShip"); // выбрасывается исключение 
        // Если пользователь ввел корректное число, то выполняется операция 
        p[i] = ves;
    }
    catch (const exception &ex)//обработчик исключений 
    {
        cerr << "Ошибка: " << ex.what() << '\n';
    }
    
}
.
Есть файл main.cpp, где она вызывается
C++
1
2
3
4
5
6
7
8
//заполняем массив данными
    for (i = 0; i < 5; i++) 
    {
        Ship ves(n_val[i], displacement_[i], t_val[i]);
        group.PutShip(i, ves);
 
 
    }
Я поняла, что нужно настроить, чтобы исключения ловились в main.cpp, верно? Но что-то не пойму как это сделать.
0
18901 / 9859 / 2410
Регистрация: 30.01.2014
Сообщений: 17,302
24.04.2021, 17:58 11
Цитата Сообщение от Ann1984 Посмотреть сообщение
Но что-то не пойму как это сделать.
Убрать из функции:
C++
1
2
3
4
5
6
7
8
//функция заносит объект ves типа Ship в i-ое место массива
void Group::PutShip(size_t i, const Ship& ves) 
{
    if (i > size) // Если пользователь ввел некорректное число, то выбрасывается исключение
        throw range_error("Group::PutShip"); // выбрасывается исключение 
    // Если пользователь ввел корректное число, то выполняется операция 
    p[i] = ves;
}
Добавить в main:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try
{
//...
 
//заполняем массив данными
    for (i = 0; i < 5; i++) 
    {
        Ship ves(n_val[i], displacement_[i], t_val[i]);
        group.PutShip(i, ves);
    }
}
catch (const exception &ex)//обработчик исключений 
{
    cerr << "Ошибка: " << ex.what() << '\n';
}
1
0 / 0 / 0
Регистрация: 09.10.2018
Сообщений: 87
06.05.2021, 07:27  [ТС] 12
Я попробовала изменить код, опираясь на Ваши комментарии.
Вот что вышло.


group.cpp
...
C++
1
2
3
4
5
6
7
8
9
//функция заносит объект ves типа Ship в i-ое место массива
void Group::PutShip(size_t i, const Ship& ves) 
{
        if (i >= size) // Если пользователь ввел некорректное число, то выбрасывается исключение
            throw range_error("Group::PutShip"); // выбрасывается исключение 
        // Если пользователь ввел корректное число, то выполняется операция 
        p[i] = ves;
    
}
...
C++
1
2
3
4
5
6
7
8
9
//перегрузка оператора индексирования
Ship& Group::operator[](size_t i)  //используем беззнаковый тип size_t
{
        if (i >= size)
            throw range_error{ "Group::operator[]" };
        return p[i];
        
};
...
main.cpp
...
C++
1
2
3
4
5
6
7
8
9
10
//проверяем перегрузку оператора 
    std::cout << "Третий корабль: ";
    try  // ищем исключения внутри этого блока и отправляем их в соответствующий обработчик catch
    {
        group[2].Print();
    }
    catch (const std::exception&ex1) //обработчик исключений 
    {
        cerr << "Ошибка: " << ex1.what() << '\n';
    }
...
Но работа не прошла, так преподаватель написала: "В перегруженный оператор [] можно передать некорректный индекс, и это не проверяется. Сейчас исправлено всё ещё не полностью. Отрицательные значения?"

Вот хочу спросить тут, а разве тип "size_t " не исключает отрицательные элементы?
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
06.05.2021, 08:42 13
Цитата Сообщение от Ann1984 Посмотреть сообщение
Вот хочу спросить тут, а разве тип "size_t " не исключает отрицательные элементы?
Исключает. Проверки if (i >= size) достаточно. Только size тоже должен иметь тип size_t
1
DrOffset
06.05.2021, 13:14
  #14

Не по теме:

Цитата Сообщение от Ann1984 Посмотреть сообщение
Отрицательные значения?
Похоже, что правильно все-таки assert не стали делать, потому что с таким уровнем преподавателя наверняка бы тоже возникли подобные неадекватные вопросы.

0
0 / 0 / 0
Регистрация: 09.10.2018
Сообщений: 87
06.05.2021, 15:42  [ТС] 15
Спасибо всем, вроде все учла .
Еще такой вопрос. Преподаватель пишет:
"В конструктор с параметрами для группы допускается сейчас передавать отрицательное или нулевое количество элементов. Аналогично далее нет проверки в функции добавления элементов в группу, можно передать любой номер. Исправлено не полностью."
Вот мой конструктор с параметрами:
group.cpp
...
C++
1
2
3
4
5
6
//конструктор объекта
Group::Group(size_t member)// используем беззнаковый целочисленный тип size_t, который никогда не бывает отрицательным
{
    size = member;
    p = new Ship[size];  //Создание объекта через указатель и динамический массив
}...
Вот функция:
group.cpp
...
C++
1
2
3
4
5
6
7
8
9
//функция заносит объект ves типа Ship в i-ое место массива
void Group::PutShip(size_t i, const Ship& ves) 
{
        if (i >= size) // Если пользователь ввел некорректное число, то выбрасывается исключение
            throw range_error("Group::PutShip"); // выбрасывается исключение 
        // Если пользователь ввел корректное число, то выполняется операция 
        p[i] = ves;
    
}
...

В main.cpp пишу:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...int i;
 
    string nval_[5] = { "Бисмарк", "Аврора", "Титаник", "Черная жемчужина", "Санта-Мария" }; //наименование
    int displacement_[5] = { 50900, 7130, 52310, 7000, 200 };//водоизмещение 
    string tval_[5] = { "корабль", "крейсер", "лайнер", "фрегат", "Каракка" };//тип
 
    Group group(5);  //создаем объект типа Group размером 5 записей
 
    try   // ищем исключения внутри этого блока и отправляем их в соответствующий обработчик catch
    {
        //заполняем массив данными
        for (i = 0; i < 5; i++)
        {
            Ship ves(nval_[i], displacement_[i], tval_[i]);
            group.PutShip(i, ves);
        }
    }
    catch (const exception &ex)//обработчик исключений 
    {
        cerr << "Ошибка: " << ex.what() << '\n';
    }...
Вот не пойму чего надо. Добавить в конструктор size != 0, но вроде лишнее. А отрицательные значения исключает тип size_t .
Подскажите пожалуйста, что я не учла или неправильно указала.
p.s. в group.h исправила тип:
C++
1
size_t size;
0
18901 / 9859 / 2410
Регистрация: 30.01.2014
Сообщений: 17,302
06.05.2021, 22:42 16
Ann1984, все у вас правильно.

Добавлено через 7 минут
Цитата Сообщение от Ann1984 Посмотреть сообщение
нулевое количество элементов
Это допустимо. В случае нуля конструкция
C++
1
new Ship[size];
вернет корректный указатель.
Разыменовывать такой указатель нельзя, но у вас от этого защищают проверки в методах PutShip и operator[].
0
51 / 149 / 33
Регистрация: 29.06.2019
Сообщений: 1,428
09.05.2021, 09:07 17
Цитата Сообщение от DrOffset Посмотреть сообщение
Убрать из функции:
Добавить в main:
? правильно ли будет моё предположение, что в функциях классов (помимо того, что в Ctor и Dtor само собой разумеющееся) тоже вообще лучше не выбрасывать исключения?.. а всё отлавливать только на стороне клиента (пользователя объектом класса)...
0
18901 / 9859 / 2410
Регистрация: 30.01.2014
Сообщений: 17,302
09.05.2021, 09:54 18
Цитата Сообщение от JeyCi Посмотреть сообщение
? правильно ли будет моё предположение, что в функциях классов (помимо того, что в Ctor и Dtor само собой разумеющееся) тоже вообще лучше не выбрасывать исключения?
Это все зависит от выбранного подхода к построению архитектуры. В общем говоря, можно и так и так делать.
1
09.05.2021, 09:54
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
09.05.2021, 09:54
Помогаю со студенческими работами здесь

Как определить наличие конструктора с заданными параметрами?
Есть шаблонный класс - обёртка вложенного объекта. Его задача: принимать объект формата JSON и...

Вызывается конструктор по умолчанию вместо конструктора с параметрами
Есть 2 конструктора: Cell::Cell() { strcpy(PhoneTouchScreen,&quot;Unknown&quot;); ...

Вызов конструктора с несколькими параметрами при использовании push_back() в vector'е
Ситуация: #include &lt;vector&gt; class bar { public: bar(); bar(int); bar(int, int);...

Программа стала работать некорректно при добавлении конструктора с параметрами
Есть задача заюзать конструктор с параметрами (см. в самом начале кода) (до его введения все...

Класс Time, конструкторы с параметрами "содержит более одного конструктора по умолчанию"
Есть такая, еще не дописанная программа. В классе объявлен конструктор с параметром &quot;Time(int...

Почему при вызове конструктора из конструктора нельзя передавать this как аргумент?
Есть такой код: public class Order { { } Order(){ ...


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

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