继续我的C ++传奇,这是我的CS1类的第三个项目:


浮力是对象浮动的能力。阿基米德原理
指出,浮力等于被水下物体置换的流体的重量。浮力可以由


$$ F_b = V \ cdot y $$

其中\ $ F_b \ $是浮力。 \ $ V \ $是
淹没对象的体积,\ $ y \ $是流体的特定重量。如果
\ $ F_b \ $大于或等于对象的重量,则
它将浮动,否则将下沉。

编写一个程序,输入球体的重量(磅)和半径(
英尺),并输出球体是否会沉入水中或漂浮在水中。使用\ $ y = 62.4 \ dfrac {\ text {lb}} {\ text {ft} ^ 3} \ $作为水的特定重量。球体的体积由\ $ \ left(\ dfrac {4} {3} \ right)\ pi r ^ 3 \ $计算。


另外,我必须有一个该程序中的循环允许用户根据需要运行它多次。我必须每次询问用户是否要继续。

它也应该被完全评论,我认为我是在合理的范围内完成的。

buoyancy.cpp

/**
 * @file buoyancy.cpp
 * @brief Calculates if a sphere will sink or float in water given the weight and radius
 * @author syb0rg
 * @date 9/12/14
 */

#include <iostream>
#include <limits>
#include <math.h>

/**
 * Sphere
 * @var weight The weight of the sphere
 * @var radius The height of the sphere
 */
struct Sphere
{
    double weight = 0;
    double radius = 0;
};

/**
 * Resets the command line so we can input data again, and signals user to re-enter proper data
 */
void resetConsole()
{
    std::cin.clear(); // clear the error flag that was set so that future I/O operations will work correctly
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // skips to the next newline
    std::cout << "Invalid input.  Please enter a positive number: ";
}

int main()
{
    constexpr double waterBuoyancy = 62.4;
    Sphere obj;
    char again = 'q4312078q';
    do
    {
        // get input for height, re-read input if not a positive number
        std::cout << "Enter the weight in pounds: ";
        while(!(std::cin >> obj.weight) || obj.weight < 0) resetConsole();

        // get input for radius, re-read input if not a positive number
        std::cout << "Enter the radius in inches: ";
        while(!(std::cin >> obj.radius) || obj.radius < 0) resetConsole();

        double volume = ((4/3) * M_PI * pow(obj.radius, 3));
        double bouyantForce = volume * waterBuoyancy;

        if (obj.weight <= bouyantForce) std::cout << "The object will float." << std::endl;
        else std::cout << "The object will sink." << std::endl;

        std::cout << "Run the program again (y/N): ";
        std::cin.get();  // absorb newline character from previous input
        std::cin.get(again);
        again = tolower(again);
        if ('\n' == again) again = 'n';
    } while (again == 'y');
}


评论

-如果她的体重与鸭子相同...-她是木头做的。 qedcat.com/moviemath/holy_grail.html

本身不值得一个答案,但您拥有球体的重量和球体的高度,并且没有指示它们使用什么单位。如果您很幸运,那么维护此代码的人都会意识到这些单元已经丢失,并对其进行了追踪。如果您不走运,他们会认为这是他们惯用的单位,您将损失十亿美元。

回复:标题-女巫漂浮。扣篮是不成功的考验

您需要将(控制台应用程序)视图与(浮力)模型分开。 ...可能有些过分,但理想情况下std :: cout不应与实际物理逻辑处于同一类。

我一直喜欢塞勒姆巫术审判的荒谬之处,尤其是下沉和漂浮的部分。 “好吧,我们将把你绑起来,把你扔进这深水里。如果你漂浮,那你是个女巫!但是如果你沉没,溺水而死,那你就没事了。所以,在这种情况下,嗯...为这个错误感到抱歉。哦,好了,你现在已经死了。哎呀。“

#1 楼

有一些小事情可以改进:


double weight = 0;可以很好地工作,但是double weight = 0.0;会更有趣,因为weightdouble

下一行是一个很好的例子,可以说明文字方法学的好处:

double volume = ((4/3) * M_PI * pow(obj.radius, 3));
在这里,4/3执行整数除法而不是浮点运算;该表达式将产生1而不是1.333333333(我怀疑您希望它产生1)。您应该将其更改为4.0/3.0以获得所需的结果。

也就是说,上述行还有另一个问题:M_PI不是标准的C ++。它也不是标准的C。它是<math.h>的标准POSIX补充。如果要使代码具有可移植性,则应重写自己的常量或使用Boost常量作为示例。

<math.h> ...您正在使用C ++,因此也应该使用C ++标准库头文件而不是C语言:

#include <cmath>


而您尤其忘了包含<ctype.h>的标头std::tolower
那是在C ++中最好的做法限定标准库中函数的名称:您应该编写std::tolower(因此实际上包括<cctype>而不是<ctype.h>)。它并不是真正更长的时间,它可能有助于防止名称冲突(我怀疑您在使用tolower时会遇到问题,但是使用一些更常用的名称可能会更糟)。


评论


\ $ \ begingroup \ $
在最后一个项目符号上-如果包含,则必须为std :: tolower,而如果包含,则必须为tolower。不要混合两者。
\ $ \ endgroup \ $
– Toby Speight
16年11月9日在16:49

\ $ \ begingroup \ $
@TobySpeight您太过学究了:p还是解决了它。
\ $ \ endgroup \ $
–莫文
16年11月9日在17:41

\ $ \ begingroup \ $
“ Pedantic”是我在工作中的中间名,特别是在检查代码时。 :-)
\ $ \ endgroup \ $
– Toby Speight
16年11月9日在17:51

#2 楼

错误

您错误地计算了球体的体积!

样式


您拼错了变量bouyantForce
常数waterBuoyancy是错误的名称。应该是waterDensity
struct Sphere没什么意义。您尚未定义任何方法,也未使用它来促进参数传递。您可能还有两个名为weightradius的自变量。 (您也可以采用另一种方法,使它成为一个类。)
代替(或除了定义resetConsole()之外),您还可以定义askDouble(promptString)函数。这样可以减少重复,并使您的main()更易于遵循。


评论


\ $ \ begingroup \ $
好点。我同意其中的大多数,但是我认为struct Sphere比具有两个独立变量更具表现力。不是出于OOP的原因,而是为了提供上下文。
\ $ \ endgroup \ $
– danijar
2014年10月11日下午0:19

#3 楼


char again = '
do 
{
    // ...
    if ('\n' == again) again = 'n';
} while (again == 'y');
';



无需设置值。您仍然要在使用前将其覆盖。


q4312078q


这里的if似乎毫无意义。如果again不是'y',则无论如何都会退出循环,因此设置again = 'n'if似乎毫无意义。

尽管为struct创建了Sphere,但在此代码中没有多大用途。 Sphere为您做的不多。设置其重量和半径,然后直接使用这些字段来计算体积。移动Sphere内的体积计算将很有意义。这样,该对象将具有更多用途:用户不必担心如何计算体积,将逻辑封装在内部。

您可以想象不同类型的对象实现适当的volume方法。您可以收集此类对象,而无需知道如何从其内部属性中计算其体积,而只需询问其volume方法即可。

#4 楼

关于struct,如果您只是要创建实例并可能将实例传递给另一个函数,则可以将其保留在main()中。请记住,在C ++中,默认情况下structpublic

添加@ 200_success所提到的内容,您可以添加更多内容,例如用于指定实例起始值的初始化列表operator>>。重载直接输入字段,而operator<<重载直接显示实例的字段。您甚至可能会发现operator>>比访问单个字段更加精简(您可以让重载一次获取两个输入值)。

基本上,您可以利用这些东西以及@janos的体积计算思路,使Sphere更具实用性。如果某物属于Sphere,则将其保留在结构中,以便用户可以让Sphere处理它。

最后的struct Sphere看起来可能像这样:

struct Sphere
{
    double weight;
    double radius;

    Sphere(double weight, double radius)
        : weight(weight)
        , radius(radius)
    {}
};

std::istream& operator>>(std::istream& in, Sphere& obj)
{
    return in >> obj.weight >> obj.radius;
}

std::ostream& operator<<(std::ostream& out, Sphere const& obj)
{
    out << "Weight: " << obj.weight;
    out << "\nRadius: " << obj.radius;
    return out;
}


(各个重载需要<istream><ostream>,而不是<iostream>。)

请注意,重载是在struct之外定义的。尽管可以将它们作为friend函数包含在内,但Scott Meyers建议尽可能使用非成员非friend

这不执行任何输入验证(operator>>可以处理验证),但是您可以根据需要实现。即使没有这些额外的代码,struct可能也更适合放在单独的文件中,但是通过这种简单的实现,它可能会有点过大。这至少应该给您一些想法。