С++ ввод значений два раза вместо одного

Я должен решить эту проблему: "создать класс для описания треугольника и трапеции с возможностью возвращать значения и находить S фигур. Объявить функцию, которая позволяет сравнивать S обеих фигур. В основной функции объявить треугольник объекта и трапецию и сравнить их площади. .." - я пытаюсь перевести это с болгарского на английский извините, если это не правильно переведено .. В любом случае, я придумал решение, но когда он просит меня ввести значение для трапеции x2 раза, и я не могу понять, почему... всегда принимает первые 3 введенных числа, но я хочу, чтобы он запрашивал ввод только один раз .. извините, если ответ очевиден enter image description here

//
//  main.cpp
//  compare S of 2 figures
//
//  Created by Георгиос Семерджиев on 17/05/22.
//

#include <iostream>
#include <cmath>
using namespace std;

class Trap // trap class with declared functions inside
{
protected:
    double a, c, h;
    void setValueTrap();
public:
    Trap();
    void Print();
    virtual double S();
};  // end trap class

class Triangle : public Trap  // triangle class with declared function for finding s() print and setting value
{
    double b;
    void setValueTriangle();
public:
    Triangle();
    void Print();
    virtual double S();
    double p(); // returning P/2
}; // end triangle class

// trap functions ...

Trap:: Trap()
{
    setValueTrap();
}

void Trap::setValueTrap()      // trap input function
{
    cout << "Trap enter a = "; cin >> a;
    cout << "Trap enter c = "; cin >> c;
    cout << "Trap enter h = "; cin >> h;
    cout << endl;
}

double Trap::S() // trap calculating and returning s()
{
    return ( (a+c) * h ) / 2;
}

void Trap::Print() // printing S() for trap
{
    cout << "Trap S = " << S();
    cout << endl;
}

// Triangle functions ..

Triangle::Triangle():Trap()
{
    setValueTriangle();
}

void Triangle::setValueTriangle()  // setting value for triangle a,b,c
{
    cout << "Triangle a = "; cin >> a;
    cout << "Triangle b = "; cin >> b;
    cout << "Triangle c = "; cin >> c;
    cout << endl;
}

double Triangle::p() // returning P / 2 = p
{
    return (a+b+c) / 2;
}

double Triangle::S() // calculating S() of triangle
{
    return sqrt(p() * (p() - a) * (p()-b) * (p()-c));
}

void Triangle::Print()
{
    cout << "Triangle S = " << S();
    cout << endl;
}

// creating function to compare Trap S() and Triangle S()

bool Compare (Trap *F1, Trap *F2)
{
    return F1 -> S() < F2 -> S();
} // compare function


int main()
{
    Trap* trap = new Trap();
    Triangle* triangle = new Triangle();
    
    trap -> Print(); triangle -> Print();
    cout << endl;
    
    if (Compare(trap, triangle))
        cout << "the Trap S < Triangle S.." << endl;
    
    else
    {
        cout << "The Trap S > Triangle S.." << endl;
    }
    
    return 0;
}

Первый для trap, второй для triangle

user253751 17.05.2022 10:30

Здесь нет причин использовать указатели и new. Вы можете создать объект Trap просто с определением Trap trap;.

Some programmer dude 17.05.2022 10:33

Ваша программа теряет память. Не используйте необработанные указатели.

Ted Lyngmo 17.05.2022 10:34

Кстати, должен ли Triangle действительно иметь все переменные-члены a, b, c и h? Является ли Triangle типом Trap?

Ted Lyngmo 17.05.2022 10:53

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

Geo48 17.05.2022 10:56

Кстати: ваш вывод игнорирует случай равенства; дополнение > равно <=, а не <...

Aconcagua 17.05.2022 10:58

ой, забыл об этом, спс

Geo48 17.05.2022 10:58

Учителя довольно часто не в курсе языков. Если вам нужно использовать указатели, предпочитающие современные умные указатели (std::unique_ptr или std::shared_ptr, в зависимости от требований). И если необработанные указатели по какой-либо причине неизбежны, то для каждого new предусмотрите соответствующий delete с самого начала. Все остальные будем приводят к утечкам памяти...

Aconcagua 17.05.2022 11:00

@Аконкагуа, спасибо! я должен добавить ловушку удаления; удалить треугольник; в конце int main() правильно?

Geo48 17.05.2022 11:05

@ Geo48 Использовал ли "похожий тип задачи" базовый класс, в котором не все переменные-члены использовались в производном классе? Да, вы должны delete их ... или лучше использовать умный указатель, например unique_ptr, который делает это автоматически. В показанном вами примере вам даже не нужны указатели. Вы можете создать их как автоматические переменные, как предложил Someprogrammerdude вверху.

Ted Lyngmo 17.05.2022 11:06

@TedLyngmo Нет, это то же самое, но вместо площади она находит периметр, а вместо трапеции и треугольника она использует ромб и круг, если я хорошо помню

Geo48 17.05.2022 11:08

@TedLyngmo, тогда зачем ей вообще использовать указатели, потому что это в теме полиморфизма или?

Geo48 17.05.2022 11:09

@ Geo48 Да, указатели хороши, если вам нужно хранить и получать доступ к своим экземплярам с помощью указателей базового класса, но ваш базовый класс не имеет деструктора virtual, поэтому их хранение в качестве указателей базового класса исключено. Кроме того, ваша функция Print не является virtual, поэтому вызов ее из указателя базового класса вызовет только базовый класс Print

Ted Lyngmo 17.05.2022 11:09

Я бы переработал эту установку. Найдите общие атрибуты все ваших фигур и поместите их в свой базовый класс. Затем наследуйте атрибуты и добавлять в производных классах, если это необходимо. Если базовый класс имеет атрибут, который вам не нужен в производном классе, вероятно, это не тот базовый класс.

Ted Lyngmo 17.05.2022 11:13

сойдет, спасибо всем за потраченное время на объяснения! ценить это!

Geo48 17.05.2022 11:16

@ Geo48 Есть несколько вариантов, как справиться с утечкой памяти. Если особые обстоятельства не делают это невозможным (например, при использовании полиморфизма или когда объекты могут стать слишком большими для стека — последнее довольно редкое явление), то проще всего создать объекты прямо в стеке: Trap trap; Triangle triangle; такие объекты будут уничтожены неявно как как только они закончатся. То же самое применимо, если вы используете интеллектуальные указатели, например. std::unique_ptr<Trap> trap = new Trap(); или как вариант auto trap = std::make_unique<Trap>();.

Aconcagua 17.05.2022 11:16

Только если у вас есть веская причина избегать интеллектуальных указателей, которые я бы использовал с необработанными указателями (примечание: вы можете использовать их при передаче объектов функциям, которые не будут владеть), тогда вы должны рассмотреть их. И да, в этом случае вам нужно явно удалить объекты, как вы упомянули для своих объектов-ловушек и треугольников...

Aconcagua 17.05.2022 11:18

@Aconcagua Пытался переделать решение, но теперь я получаю эту ошибку .. pastebin.com/MjJy831ibb.co/WfcFx8C

Geo48 17.05.2022 11:57

@Geo48 Такая ошибка обычно возникает, если вы забыли реализовать одну из виртуальных функций (или сделать ее чисто виртуальной), или, может быть, вы пытаетесь dynamic_cast, в то время как ShapeBase вообще не имеет информации RTTI из-за отсутствия виртуальной членов (затем добавьте хотя бы виртуальный деструктор).

Aconcagua 17.05.2022 12:17

@Aconcagua Я пытался поискать где-то в Интернете, как это сделать, но не смог исправить это сам, когда у вас будет время, я был бы очень, очень благодарен, если бы вы показали мне, как это сделать в моем коде ^. , Даже если нет, еще одно спасибо за всю помощь!

Geo48 17.05.2022 12:43

@Geo48 Minimalistic пример — также иллюстрирует, как конструкторы вызываются один за другим (ваша исходная проблема; обратите внимание на двойной вывод, один раз из Triangle t;, а затем снова из new Triangle())... Не уверен, что вам нужно еще. Не уверен, что это BaseShape поможет вам вообще — есть ли у вас братья и сестры Trap в иерархии классов (по крайней мере, в уме, так что только концептуально)? Если нет, то мне это не кажется оправданным. Вместо этого добавьте явный виртуальный деструктор в класс Trap...

Aconcagua 17.05.2022 13:32

Для полноты: Расширенный пример, иллюстрирующий вызов деструкторов в обратном порядке - и порядок уничтожения элементов относительно друг друга... Не стесняйтесь немного поиграть, чтобы узнать подробности;) (Примечание: если вы правильно управляете памятью , т. е. нет утечек памяти, то количество уничтоженных объектов должно быть равно количеству созданных объектов.)

Aconcagua 17.05.2022 13:43
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
0
22
30
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Triangle наследуется от Trap, и оба их конструктора вызываются при создании объекта Triangle. Чтобы избежать этого, настройте виртуальную функцию setValue и назовите ее Только в Trap конструкторе.

Вызов виртуальной функции в конструкторе Trap вызывает версию функции Trap.

user253751 17.05.2022 10:41

если я вызову виртуальную функцию в ловушке для установки значений, мне не нужно будет устанавливать значение h в треугольнике, а также значение b в ловушке, где они мне не нужны?

Geo48 17.05.2022 10:42

@Geo48 Честно говоря, забудьте об этой идее. Когда Trap создается, он по-прежнему является Только объектом Trap, поэтому, как уже упоминалось, вызывается не переопределенная версия Triangle, а версия Trap. Таким образом, виртуальная она или нет, это всегда будет та же самая версия, которая называется...

Aconcagua 17.05.2022 11:07

@ Geo48 Если вы хотите работать с виртуальными функциями, тогда первый создает объект, потом вызывает виртуальную функцию, например. как Triangle t; t.setValue();.

Aconcagua 17.05.2022 11:09
Ответ принят как подходящий

Для конструктора Triangle у вас есть:

Triangle::Triangle():Trap()
{
    setValueTriangle();
}

Это явно вызовет конструктор Trap, который считывает ввод. Затем вы прочитаете ввод для треугольника.

Часто не рекомендуется читать ввод в конструкторе. Обычно лучше выполнить только базовую инициализацию в конструкторе, а затем получить ввод, используя полностью сконструированный объект.


Обратите внимание, что даже если у вас нет явного вызова конструктора Trap, это произойдет неявно.

Я не люблю говорить новичкам, что «делать X — плохая идея», потому что они обычно не понимают, почему, а затем не делают X, даже если это хорошая идея. Я ограничиваю такие утверждения конкретным обсуждаемым кодом, где X не работает.

user253751 17.05.2022 10:40

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

Aconcagua 17.05.2022 11:03

Другие вопросы по теме

Используют ли предварительно скомпилированные заголовки предварительно скомпилированные заголовки, если они включены, или они предназначены только для файлов .cpp?
Введите каламбур в константном / статическом инициализаторе (построение константы с плавающей запятой из битов)
Могу ли я добавить другую функцию, определенную в моем коде, в вектор, такой как массивы, которые включают адрес функции?
Есть ли способ «сбросить» переменные функций?
Ошибка C2679: бинарный '>>': оператор не найден
Не удается вызвать указатель функции структуры на метод класса
Как работает параметр приблизительноPolyDP и эпсилон?
Как вставить запись в Microsoft Access с помощью MFC?
Включение предварительно скомпилированного заголовка и непредварительно скомпилированного заголовка в файл .cpp приводит к тому, что файл .cpp не распознает непредварительно скомпилированный заголовок.
Привязка rvalue ref к строковому литералу в конструкторе по сравнению с построением на месте