Декартовы/полярные координаты программу


Я могу получить мою программу проверяется на эффективность? Как, увидеть, если есть более эффективные способы написания кода, например, более эффективное использование памяти и/или параметры безопасности, как где использовать константы?

main.cpp

// MAIN.CPP
//
#include "Force.h"
#include "require.h"
#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

int main()
{   
    //Read in values from "ForceList.txt"
    char ctpe;
    double real1, real2;
    vector<Force> forceCol;
    ifstream in("ForceList.txt");
    assure(in, "Forcelist.txt");    //verify its open

    //Store forces in vector 'forceCol' in cartesian as default
    while (in >> ctpe >> real1 >> real2) {
        Force cart(ctpe, real1, real2);
        if (ctpe == 'c' || ctpe == 'C') {
            forceCol.push_back(cart);
        }
        else if (ctpe == 'p' || ctpe == 'P') {
            cart.converter();
            forceCol.push_back(cart);
        }
    }

    in.close();

    // Print the forces in vector 'forceCol' in cartesian form.
    cout << "Cartesian:\n" << endl;
    cout << "No." << "              x." << "          y. \n";
    for (unsigned int i = 0; i < forceCol.size(); ++i) {
        cout << "Force " << i + 1 << ":";
        forceCol[i].print();
    }

    //Convert 'forceCol' into polar form.
    for (unsigned int i = 0; i < forceCol.size(); ++i) {
        forceCol[i].converter();
    }


    // Print the forces in vector 'forceCol' in polar form.
    cout << endl << "---------------" << endl;
    cout << "\nForces in polar:\n" << endl;
    cout << "No." << "            Radius." << "     Angle. \n";
    for (unsigned int i = 0; i < forceCol.size(); ++i) {
        cout << "Force " << i + 1 << ":";
        forceCol[i].print();
    }

    //Convert back to cartesian for calculations
    for (unsigned int i = 0; i < forceCol.size(); ++i) {
        forceCol[i].converter();
    }

    //Summate the forces in 'forceCol' and print the result in cartesian form.
    Force summedForce;
    for (unsigned int i = 0; i < forceCol.size(); ++i) {
        summedForce = summedForce + forceCol[i];
    }
    cout << endl << "---------------" << endl;
    cout << "\nThe summed force in cartesian form is: " << endl;
    summedForce.print();

    //Convert 'summedForce' to polar form and print.
    summedForce.converter();
    cout << "\nThe summed force in polar form is: " << endl;
    summedForce.print();

    //Print out the resultant force of the first 3 forces in cartesian form
    Force resultantForce;
    resultantForce = -(forceCol[0] - forceCol[1] + forceCol[2]);
    cout << "\nThe resultant force of the first 3 forces in cartesian form is: " << endl;
    resultantForce.print(); 

    //Convert 'resultantForce' to polar form and print.
    resultantForce.converter();
    cout << "\nThe resultant force of the first 3 forces in polar form is: " << endl;
    resultantForce.print();
    cout << endl;

}

Силу.ч

#ifndef Force_H
#define Force_H

#include <iostream>
#include <iomanip>
#include "require.h"

//Question 1 - Class 'Force' that reads in cartesian or polar coordinates,
//can discern which is which, and allows conversion and arthithmetical manipulation

class Force {
    char coType; // Type of coordinate - cartesian or polar
    double r1;  // 1st real number
    double r2;  // 2nd real number
public:
    //Constructor that reads in the files and checks that the first value is 'c, C, p or P'
    //and assign defeauts
    Force(char coType1 = 'c', double re1 = 0.0, double re2 = 0.0) :
        coType(coType1), r1(re1), r2(re2) {
        require(coType1 == 'p' || coType == 'P' || coType == 'c' || coType == 'C');
    };
        ~Force() {};

    //Binary operators for addition and subtraction of 'Force' objects values.
    Force operator+(Force& fo){
        return Force(coType = fo.coType, r1 + fo.r1, r2 + fo.r2);
    };
    Force operator-(Force& fo){
        return Force(coType = fo.coType, r1 - fo.r1, r2 - fo.r2);
    };
    //Unary operator to change the sign of the objects values.
    Force operator-()
    {
        return Force(coType, r1 = -r1, r2 = -r2);
    }

    //Accessors
    char get_coType() const { return coType; }
    double get_r1() const { return r1; }
    double get_r2() const { return r2; }

    //mutators 
    void set_coType(char c) { coType = c; }
    void set_r1(double a) { r1 = a; }
    void set_r2(double b) { r2 = b; }

    //printer
    int print() {
        using namespace std;
        cout << setprecision(2) << fixed;
        cout << coType << setw(10) << right << r1 << setw(10) << right << r2 << endl;
        return 0;
    }

    //Converter
    void converter();
};


#endif

Force.cpp

#include "Force.h"
#include <cmath>

using namespace std;

//Converter function
void Force::converter() {

    //Pass by reference to change original values 
    double& x = r1;
    double& y = r2;
    double& rad = r1;
    double& theta = r2;

    //'Intermeditary' variables
    double x1 = x;
    double y1 = y;
    double rad1 = rad;
    double theta1 = theta;

    //Check which type of coordinates are being converted 
    //intermeditary variables used to stop math errors in the conversion
    if (coType == 'c' || coType == 'C') {
        coType = 'p';
        rad = hypot(x1, y1);
        theta = atan2(y1, x1);
    }
    else if (coType == 'p' || coType == 'P') {
        coType = 'c';
        y = rad1 * sin(theta1);
        x = rad1 * cos(theta1);

    }


};

ForceList.txt

p 10 0.5
c 12 14
p 25 1
p 100. 0.80
c 50. 50.
p 20 3.14
c -100. 25
p 12 1.14

Первое письмо, что типа силы декартовых или полярных, следующие 2 цифры-координаты декартовой и величину и угол полярной



Комментарии
3 ответа

Вот некоторые комментарии, которые могут помочь вам улучшить ваш код.

Понять разницу между <cmath> и <math.h>

Разница между двумя формами в том, что первый определяет вещи в std:: против имен в глобальное пространство имен. Язык юристов иметь много веселья с этим, но для ежедневного использования я рекомендую использовать <cmath> а затем, чтобы использовать функции, определенные есть, явно использовать пространства имен. То есть, пишите std::atan2 вместо обычного atan2. Вижу это так вопрос для деталей.

Не злоупотреблять using namespace std

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

Пересмотреть дизайн класс

Класс требует от пользователя следить за тем, какие данные и использовать converter() функция изменить из полярных в прямоугольные и обратно. Это не хороший дизайн класс. Лучше было бы сохранить внутреннее представление в любом формате, который удобен для вас и только применить преобразования на вход или выход. Кроме того, в C++ это не JAVA. Не делайте "аксессоры" и "мутаторы" для каждого элемента-членов. Если это то, что вам действительно нужно (и обычно это не так), просто использовать обычный struct вместо class. Если что еще не ясно, следующие пункты должны сделать это ясно.

Используйте std::complex класс

Многое из того, что вы реализуете уже существует в std::complex класс шаблона. Я рекомендую, что пока и если вам нужно пройти трех или более измерений. Все будет гораздо проще, если вы объявляете Force класс такой:

class Force : public std::complex<double> { /*...*/ }

Использовать const где практические

Я бы не ждал print рутинные изменения базовых Force на котором он работает, и в самом деле это не так. Вы должны сделать это ожидание явно с помощью const ключевое слово:

int print() const;

Это заявляет, что print не изменить Force, давая понять, как компилятор и человеческого читателя кода.

Не использовать std::endl если вы действительно не нужно

Разница между std::endl и '\n' это '\n' просто излучает символ новой строки, в то время как std::endl на самом деле сбрасывает поток. Это может быть трудоемким в программе с большим количеством операций ввода-вывода и редко на самом деле нужно. Лучше всего использовать std::endl когда у вас есть хорошая причина, чтобы сбросить поток, и он не очень часто нужен для простых программ, таких как этот. Избегая привычки использования std::endl когда '\n' будет ли будет выплачивать дивиденды в будущем, как вы писать более сложные программы с более ввода/вывода и, когда производительность должна быть максимальной.

Используйте конкатенацию строк

В main функция включает в себя следующие линии:

cout << endl << "---------------" << endl;
cout << "\nForces in polar:\n" << endl;
cout << "No." << " Radius." << " Angle. \n";

Вот несколько вызовов operator<< где только один является действительно требуется. Я мог бы написать ее следующим образом:

std::cout << "\n---------------\n" 
"\nForces in polar:\n\n"
"No."
" Radius."
" Angle. \n";

Это уменьшает всю вещь в один вызов operator<< потому что последовательных строк в C++ (и C, если на то пошло) автоматически объединяются в одну строку с помощью компилятора.

Вы запустите проверку орфографии на комментарии?

Если вы запустите проверку правописания на вашем комментарии, вы найдете целый ряд вещи, такие как "arthithmetical", а не "арифметическая" и "intermeditary" вместо "посредник". Поскольку ваш код достаточно хорошо прокомментирован, это стоит дополнительных шаг, чтобы устранить орфографические ошибки.

Не жестко кодировать имена файлов

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

Предпочитаете поток экстрактор для ручного ввода

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

friend std::istream &operator>>(std::istream &in, Force &f);

Затем в течение mainвы можете использовать его как это:

std::vector<Force> forceCol;
{
std::ifstream in(argv[1]);
Force f;
while (in >> f) {
forceCol.push_back(f);
}
}

Обратите внимание, что большинство линий в этом фрагменте заключены в скобки. Это намеренное, так что in и f выйдет из области видимости и автоматически уничтожается, когда код достигает закрывающей фигурной скобкой. Это означает, что нет необходимости в явном файл закрыть.

Использовать стандартные алгоритмы

Вместо того, чтобы писать цикл, как это:

Force summedForce;
for (unsigned int i = 0; i < forceCol.size(); ++i) {
summedForce = summedForce + forceCol[i];
}

Вместо этого вы могли бы написать это так:

Force summedForce{std::accumulate(forceCol.begin(), 
forceCol.end(),
Force{})
};

Написать две разные программы

Как уже упоминалось ранее, а не изменение внутренней структуры Forceпросто создайте две разных программы такой:

std::string asCart() const;
std::string asPolar() const;

В данном случае, я избран, чтобы создать и вернуть std::stringно можно также легко пройти std::ostream & в (и вне). Теперь пользователю не нужно заботиться о внутреннем представлении, а просто спрашивает конкретно для нужной форме.

3
ответ дан 14 апреля 2018 в 07:04 Источник Поделиться

В вашем классе, оседают на набор юнитов, и использовать это для своего внутреннего хранения.

Есть специфические методы для входов, например SetPolar, SetCartesian. Вы можете использовать три подхода к конструктору, который может затем вызвать двух способов ввода в зависимости от того, c или p передается (сокращения дублирования в коде).

Ваши конкретные методы ввода сделать преобразования из числа пользователей к выбранной единицы. (например, если вы выбрали полярного, то не сильно конверсии требуется SetPolar).

Вы также должны иметь определенные свойства, например GetPolar, GetCartesian это преобразование от выбранной единицы, чего хочет пользователь.

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

1
ответ дан 13 апреля 2018 в 09:04 Источник Поделиться

Включить предохранитель слишком легко схлестнулись с чужого файла, когда это используется. Использовать #pragma onceили если охранник действительно необходимо, использовать идентификатор UUID.


В coType лучшее перечисление, а не char.


Не пишите пустой деструктор. Оставить его полностью отключить, либо использовать =default чтобы подчеркнуть, что она существует. Вы сделали свой класс, чтобы не быть trivally destructable из-за этого, что означает, что компилятор может сделать некоторые оптимизации (это упрощение более).


Узнать canonocal способ записи арифметических операторов. То есть, сделать += член а потом пиши + С точки зрения ИТ; и т. д. У вас даже нет параметра справа: почему не могу кого-то добавить константное значение?

void foo (const Force& a, const Force& b)
{
Force c = a + b; // fails to compile!

Ваши операторы полагая, что доводы в представлении декартовой. Он будет получать неправильные результаты, если в полярных.


Будет что-то вроде

Force baz (const Force& in)
{
Force res;
res = baz;
return res;
}

компилировать? Почему нет? Перейти свой перечень функций, которые нужны в классе.


set_coType глупо. Это бессмысленно, чтобы изменить это без изменения существующего значения. Теперь, если вы имели функцию для изменения внутреннего представления в форме, что бы быть лучше.

Имея set_r1, set_r2 это не нормальная вещь для простого числового класса, как это. Вы обычно просто сформировать новое комплексное число, не менять одну из частей существующего значения.

Е. Г. чтобы получить комплекс конъюгат zнапишите силу{'с', з.Р1-з.Р2};
но сейчас вы видите еще один вопрос; нет никакого способа, чтобы гарантировать, что я в формат с, Начнем с того, ни способ, чтобы преобразовать его в режим c.

Если бы у нас было доступа , как real, imag, abs, arg тогда возвращать нужное значение, будет ли храниться или вычисляться. Е. Г. если бы у меня был полярный значение, real будет вычислять его от Полярного информации; если он был декартово значение, он просто возвращает первый сохраненный номер.

Я предлагаю моделирование комплексных чисел на класса стандарт, связанного в предыдущем пункте.


Не пишите using namespace std;


Ваш converter функция, которая переключается с одного на другое представление является слишком сложным, и не очень полезно, когда вы не можете сказать, какая форма вам начать. Е. Г.

void bar (const Force& f1)
{
// I want that in polar mode.
Force f2= f1;
if (/* what?? no accessor defined to check for that */)
f2.convert();

Вместо этого, есть способ, чтобы преобразовать в полярные независимо от того, что я начну с: если уже в Полярном, это легко! Внутри есть две отдельные функции с различными переменными; ваш x, y, ⋯ x, rad1 просто слишком замутнен, чтобы заниматься.

Ваш комментарий “переменные intermeditary используется для остановки математические ошибки в преобразовании” заставляет меня думать, что вы просто добавили их решить проблему. Объявив все переменные, которые вы, возможно, потребуется в верхней части функция-это плохо. Если вы заявили, в случае необходимости, вы видите, вам понадобится только половина из тех, кто в каждой ветке.

И функции, чтобы сделать преобразование должно быть (барабанная дробь...) конструктор!

Force f2 {f1,'P'};

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


print должна быть функция-член, которая не является основной частью класса. А что с инт возвращение это всегда ноль?

Если вам нужно сделать его членом для печати coTypeвы должны принять это как знак, что публичный API не хватает нужных возможностей использовать класс эффективно (например, возврат что текущий режим).

А почему бы не разрешить печатание const значения?

0
ответ дан 13 апреля 2018 в 10:04 Источник Поделиться