我的作业问题指出:


开发一个类来测量距离,以英尺(应为int),英寸(应为float)为单位。包括用于设置和获取属性的成员函数。包括
构造函数。开发将两个距离相加的函数。

sum函数的原型是:

Distance Sum(Distance d);



请查看我的编码风格以及可以使该程序更好的其他方面。

#include <iostream>
using namespace std;
class Distance
{
        private:
                int feet;
                float inch;
        public:
        Distance();
        Distance(int a,float b);
        void setDistance();
        int getFeet();
        float getInch();
        void distanceSum(Distance d);
};
int main()
{
        Distance D1,D2;
        D1.setDistance();
        D2.setDistance();
        D1.distanceSum(D2);
        return 0;
}
/*Function Definitions*/
Distance::Distance()
{
        inch=feet=0;
}
Distance::Distance(int a,float b)
{
        feet=a;
        inch=b; 
}
void Distance::setDistance()
{
        cout<<"Enter distance in feet";
        cin>>feet;
        cout<<endl<<"Enter inches:";
        cin>>inch;
}
int Distance::getFeet()
{
        return feet;
}
float Distance::getInch()
{
        return inch;
}
void Distance::distanceSum(Distance d)
{
        cout<<"feet="<<d.feet+feet<<endl;
        cout<<"inches="<<d.inch+inch<<endl;
}


评论

如今,空白很便宜:不要害怕使用它。

#1 楼

在为程序设计类时,无论是用于家庭作业还是用于实际的生产应用程序,您都希望始终考虑该类将如何使用以及应承担的责任。每个函数和方法都应该做一件事情/任务,并且应该由方法的名称反映出来。此外,在实际开始编写代码时,您希望保持一致的易于阅读的编码风格。考虑到这两点,在代码中需要考虑一些事项:




Distance::distanceSum在这里执行两项任务。

这不仅是求和英尺和英寸,但也会打印出来。


不必要的类型转换。

在默认的Distance()ctor中,存在一个隐式转换,因为您要将0分配给浮点类型。您应该已经从编译器得到警告。考虑使用这样的初始化列表:

Distance::Distance() : feet(0), inch(0.0)
{
}



代码没有利用const正确性。

哪些参数不需要更改?哪些方法将修改您的Distance类?例如,您的Distance::Distance(int a,float b)并未更改ab。让编译器使用const来实现承诺:

Distance::Distance(const int a, const float b)


相似:

void Distance::distanceSum(const Distance &d);



缩进和间距不一致。

考虑在public下缩进方法:与private:相同。在您的作业中添加空格以提高可读性。例如。 feet = a;


没有按文件分隔的模块。

Distance应该应该在单独的头文件/实现文件中,而不是将所有内容都放在一个主文件中。 />

忍者评论。

评论?有何评论?究竟。考虑在Distance类的顶部添加一个块注释,以解释其存在的目的。块注释应该回答这样的问题,例如该类应该如何使用以及它抽象了什么细节?添加注释以阐明英尺和英寸数据成员将如何使用。例如,不清楚您的距离等级是保持相同的距离测量值,还是使用不同的单位,还是真的打算将其用作一个整体单位。例如。 6英尺2英寸还是6英尺72英寸?

基于上述考虑,这是我重构代码的一种方法:

在distance.h头文件中:

#ifndef DISTANCE_H
#define DISTANCE_H
class Distance
{
    private:
       // feet and inch is one unit. 
       // invariant: inch_ < 12.
       int   feet_;
       float inch_;
    public:
       Distance(const int feet = 0, const float inches = 0.0);
       void      setDistance(const int feet, const float inches = 0.0);
       int       getFeet() const;
       float     getInch() const;

       // returns this instance. Permits method chaining for Distance class.
       Distance& Add(const Distance &d);
};
#endif


在distance.cpp实现中:

#include "distance.h"
Distance::Distance(const int feet, const float inches) 
         : feet_(feet + inches / 12), inch_(inches % 12)
{
}

void Distance::setDistance(const int feet, const float inches)
{
    feet_ = feet + inches / 12;
    inch_ = inches % 12;
}

int Distance::getFeet() const
{
    return feet_;
}

float Distance::getInch() const
{
    return inch_;
}

Distance& Distance::Add(const Distance &d)
{
    setDistance(getFeet() + d.getFeet(), getInch() + d.getInch());

    return *this;
}


以下是上面的主要更改:


距离不再将cin / cout用于显式IO。您可以将该代码放入main中。
类定义和实现现在位于它们各自的命名文件中。
通过利用默认参数删除了额外的构造函数定义。
feet和inch数据成员是一起用于表示距离测量。英寸不能大于12,因为那意味着有足够的一只脚。设置距离数据时,我们将英尺和英寸除以12来执行此操作。
const用于清楚地指示可以更改对象和不能更改距离的对象。
将distanceSum更改为Add可以更好地反映其作用。请注意,Add仅通过Distance的公共方法实现-不会直接操作feet_inch_


评论


\ $ \ begingroup \ $
为什么下划线是脚?(feet_)
\ $ \ endgroup \ $
–user1211
2011年1月31日上午8:19

\ $ \ begingroup \ $
@fahad只是我正在使用的编码约定,为类数据成员附加_。您当然可以选择适合您的其他约定。无论选择哪种方式,都要保持一致。
\ $ \ endgroup \ $
–狼人
2011年1月31日8:23



\ $ \ begingroup \ $
我认为未修改的函数参数不需要为const-我只会将函数本身标记为const。
\ $ \ endgroup \ $
– DeadMG
2011年1月31日上午9:48

\ $ \ begingroup \ $
是的,我也有同样的疑问!当通过值传递时,您无需保持其常量
\ $ \ endgroup \ $
–user1211
2011年1月31日12:50

\ $ \ begingroup \ $
const float inch = 0.0应该为0.0f,否则将进行隐式转换以从double浮起
\ $ \ endgroup \ $
– John Dibling
2011年1月31日20:40

#2 楼

没有必要同时使用英寸和英尺,因为一个可以从另一个计算出来。多余的冗余只会增加复杂性。

评论


\ $ \ begingroup \ $
为什么这不是我的主要评论。尽管有很多可能的改进,如Vicors的详细解释中所提到的那样,但这还是很不错的。无论您做什么,都请先解决此问题(然后事情会变得简单得多)
\ $ \ endgroup \ $
–马丁(Martijn)
2011-2-5在0:18

\ $ \ begingroup \ $
也许是因为作业的第一句话指出,班级应该分别模拟英尺和英寸。我很久以前就学会了完成作业所要求的工作,除非我确定分频器会接受优化。
\ $ \ endgroup \ $
– David Harkness
2011-2-15在8:56

\ $ \ begingroup \ $
@David-引用为作业的文本没有这么说。
\ $ \ endgroup \ $
– anon
2011-2-15在19:31

\ $ \ begingroup \ $
@Crazy Eddie-第一句话专门说明了两个属性的数据类型:“开发一个类来测量距离,以英尺(应为int)和英寸(应为float)为单位。”第二句使用复数形式表示至少两个属性:“包括用于设置和获取属性的成员函数”。我不知道它将谈论什么其他属性。
\ $ \ endgroup \ $
– David Harkness
2011-2-15在21:33

#3 楼

其中一些函数应该是运算符。您似乎也对加法的目的感到困惑。另外,using namespace std不好。您也没有提供任何其他运算符-即使任何类用户在逻辑上期望如果您可以添加距离,也可以向当前对象添加距离,也可以减去距离。您也没有提供任何类型的输入验证或const正确性。

class Distance
{
    int feet;
    float inch;
public:
    // Constructors
    Distance();
    Distance(int a, float b);

    // Getters
    int getFeet() const;
    float getInch() const;

    // Operator overloads - arithmetic
    Distance operator-(const Distance&) const;
    Distance& operator-=(const Distance&);
    Distance operator+(const Distance&) const;
    Distance& operator+=(const Distance&);

    // Create from console
    static Distance getDistanceFromConsole();
};
// Operator overloads - I/O
std::ostream& operator<<(std::ostream&, const Distance&);


实现是...

Distance::Distance() : feet(0), inch(0.0f) {}
Distance::Distance(int argfeet, float arginch) : feet(argfeet), inch(arginch) {
    // Verify that we are actually in feet and inches.
    // Not gonna write this code- dependent on the class invariants
    // which were not explicitly specified (e.g., can have negative Distance?)
}
int Distance::getFeet() const {
    return feet;
}
float Distance::getInch() const {
    return inch;
}
Distance Distance::operator-(const Distance& dist) const {
    Distance retval(*this);
    retval -= dist;
    return retval;
}
Distance& Distance::operator-=(const Distance& dist) {
    feet -= dist.feet;
    inches -= dist.inches;
    // Verify values- e.g. that inches is less than 12
    return *this;
}
Distance operator+(const Distance& dist) const {
    Distance retval(*this);
    retval += dist;
    return retval;
}
Distance& operator+=(const Distance& dist) {
    feet += dist.feet;
    inches += dist.inches;
    // More verification here.
}

std::ostream& operator<<(std::ostream& output, const Distance& dist) {
    output << "Feet: " << dist.feet << "\n";
    output << "Inches: " << dist.inches << std::endl; // flush when done.
    return output;
}

Distance getDistanceFromConsole() {
    int feet; float inch;
    std::cout<<"Enter distance in feet";
    std::cin>>feet;
    std::cout<<endl<<"Enter inches:";
    std::cin>>inch;
    return Distance(feet, inch);
}


#4 楼

C ++注释:

首选初始化列表:

Distance::Distance()
    :feet(0), inch(0)
{
        // NOT THIS -> inch=feet=0;
}


常规编码注释:

不要组合功能:
您应该定义一个函数来添加Distance对象,并打印一个对象。 (DeadMG的内容已在上面进行了介绍。)

void Distance::distanceSum(Distance d)
{
        cout<<"feet="<<d.feet+feet<<endl;
        cout<<"inches="<<d.inch+inch<<endl;
}


我还看到您没有将结果标准化。您可能有1英尺300.05英寸。每当对象的状态发生变化时,一个参数就会流入另一个参数,您应该对数据进行规范化。有一个明确的函数可以这样做,并在每次状态更改时调用它:

private: void Normalize() { int eFeet = inches / 12; feet += eFeet; inches -= (eFeet * 12);}


实现注释:

但是又为什么要存储实际上是两个不同变量(英尺和英寸)中的单个值。为什么不只存储总距离(以英寸为单位)(然后在进/出途中进行转换)。看unix时间。它只是计算自纪元以来的秒数。所有其他值都从此计算。

#5 楼

我也更喜欢先编写公共方法,因为当您检查大型类时,必须滚动查看公共成员。

例如:

class MyClass
{
public:
// public members
protected:
// protected members
private:
// private members
}


#6 楼

您可能已经在定义方法模板的类本身中编写了方法的实现。在类中编写所有这些方法通常是一个好习惯。就您而言,即使您在类之外编写了方法,C ++编译器也会在编译时将其内联。因此,最好将这些方法编写为内联方法。这将使执行速度更快,并且将取消使用看似困难的范围解析运算符。下面是如何编写示例。它仅包含一种方法,但其余方法也可以这样做。

#include <iostream>
using namespace std;
class Distance
{
    private:
            int feet;
            float inch;
    public:
    Distance()
    {
        inch=feet=0;
    }
    Distance(int a,float b);
    void setDistance();
    int getFeet();
    float getInch();
    void distanceSum(Distance d);
};
int main()
{
    Distance D1,D2;
    D1.setDistance();
    D2.setDistance();
    D1.distanceSum(D2);
    return 0;
}


这是更好的方法。所有的类方法都应该仅在该类中定义。
假设只用Java开发一个类,那么就不能通过这样的编写来开发一个好的类。