Klasse für die Entfernungsmessung in Fuß und Zoll

38517
Fahad Uddin

In meiner Hausaufgabenfrage heißt es:

Entwickeln Sie eine Klasse, um die Entfernung so zu messen, wie Fuß (sollte int), Zoll (sollte float) sein. Fügen Sie Elementfunktionen ein, um Attribute festzulegen und abzurufen. Konstruktoren einschließen Entwickeln Sie Funktionen, um zwei Abstände hinzuzufügen.

Der Prototyp der Summenfunktion lautet:

Distance Sum(Distance d);

Bitte überprüfen Sie meinen Codierstil und andere Aspekte, die dieses Programm verbessern können.

#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;
}
Antworten
27
Whitespace ist heutzutage billig: Scheuen Sie sich nicht, es zu benutzen. pmg vor 9 Jahren 0

6 Antworten auf die Frage

27
greatwolf

Wenn Sie eine Klasse für Ihr Programm entwerfen, sei es für Hausaufgaben oder für eine reale Produktionsanwendung, möchten Sie immer darüber nachdenken, wie diese Klasse verwendet wird und wie ihre Verantwortlichkeiten aussehen sollten. Jede Funktion und Methode sollte eine Sache / Aufgabe erfüllen und sich im Namen der Methode widerspiegeln. Darüber hinaus möchten Sie einen konsistenten, leicht lesbaren Codierstil beibehalten, wenn Sie tatsächlich mit dem Schreiben des Codes beginnen. Im Hinblick auf diese beiden Punkte sind im Code einige Punkte zu beachten:

  • Distance::distanceSum macht hier zwei Aufgaben.

Es summiert nicht nur Fuß und Zoll, sondern druckt sie auch aus.

  • Unnötige Typkonvertierung

In Ihrem standardmäßigen Distance () -Cor gibt es eine implizite Konvertierung, da Sie 0einem Float-Typ zuweisen . Sie sollten eine Warnung von Ihrem Compiler erhalten haben. Erwägen Sie die Verwendung einer Initialisierungsliste wie folgt:

Distance::Distance() : feet(0), inch(0.0)
{
}
  • Code nutzt die const-Richtigkeit nicht aus.

Welche Parameter ändern sich nicht? Welche Methoden werden Ihre Distance-Klasse ändern? Zum Beispiel Distance::Distance(int a,float b)ändert sich nicht aoder b. Lassen Sie den Compiler dieses Versprechen mit const erzwingen:

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

Ähnlich:

void Distance::distanceSum(const Distance &d);
  • Inkonsistente Einrückung und Abstand.

Betrachten Sie die Einrückung der Methoden unter public: genauso wie bei private :. Fügen Sie Ihren Zuweisungen Leerzeichen hinzu, um die Lesbarkeit zu verbessern. z.B.feet = a;

  • Keine Modultrennung nach Datei.

Die Klasse Distancesollte sich wahrscheinlich in einer separaten Header- / Implementierungsdatei befinden, anstatt alles in einer Hauptdatei abzulegen.

  • Ninja-Kommentare

Bemerkungen? Welche kommentare Genau. Fügen Sie am Anfang Ihrer Distance-Klasse einen Blockkommentar hinzu, der den Zweck seiner Existenz erläutert. Der Blockkommentar sollte Fragen beantworten, wie diese Klasse verwendet werden soll und welche Details abstrahiert sie? Hinzufügen eines Kommentars, um zu erläutern, wie die Datenelemente für Fuß und Zoll verwendet werden. Es ist zum Beispiel nicht klar, ob Ihre Abstandsklasse die gleiche Abstandsmessung hat, jedoch mit unterschiedlichen Einheiten oder wirklich als eine ganze Einheit verwendet werden soll. z.B. 6 Fuß 2 Zoll oder 6 Fuß 72 Zoll?

Mit den obigen Überlegungen möchte ich den Code so umgestalten:

In der Datei 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

In der distance.cpp-Implementierung:

#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;
}

Hier sind die wichtigsten Änderungen oben:

  • Distance verwendet Cin / Cout nicht mehr für explizite IO. Sie können diesen Code in main eingeben.
  • Klassendefinition und Implementierung befinden sich jetzt in ihren jeweils benannten Dateien.
  • Eine zusätzliche Konstruktordefinition wurde unter Verwendung der Standardparameter entfernt.
  • Datenelemente in Fuß und Zoll werden zusammen verwendet, um die Messung in der Entfernung darzustellen. Zoll kann nicht> 12 sein, da dies für einen Fuß ausreichend wäre. Wir erzwingen dies, indem wir beim Einstellen der Entfernungsangaben Fuß und Zoll durch 12 teilen.
  • const wird verwendet, um eindeutig anzugeben, was das Entfernungsobjekt ändern kann und nicht.
  • DistanceSum wurde in Add geändert, um besser anzuzeigen, was es tut. Beachten Sie, dass hinzufügen nur durch öffentliche Methoden Entfernung des umgesetzt - es nicht manipulieren feet_und inch_direkt.
Warum ein Unterstrich in Füßen? (Feet_) Fahad Uddin vor 10 Jahren 0
@fahad, das ist nur eine Codierungskonvention, die ich verwende und _ für Klassendatenmitglieder anhängt. Sie können sicherlich eine andere Konvention wählen, die zu Ihnen passt. Was auch immer Sie wählen, bleiben Sie konsequent. greatwolf vor 10 Jahren 1
Ich denke nicht, dass unmodifizierte Funktionsargumente const sein müssen - ich würde nur die Funktionen selbst als const kennzeichnen. DeadMG vor 10 Jahren 2
Ja, ich hatte den gleichen Zweifel: Wenn man den Wert übergibt, muss man ihn nicht konstant halten Fahad Uddin vor 10 Jahren 0
Eine Sache, die Victor T. impliziert, aber nicht ausdrücklich erwähnt, ist, dass Sie keine Einrückungen von 8 Leerzeichen verwenden müssen. 4 Felder sind eine übliche Konvention. 8 Felder sind eine unnötige Verschwendung Ihres wertvollen horizontalen Raums. doppelgreener vor 10 Jahren 0
Ich bin kein C ++ - Typ, also nicht sicher über die 'neue' Syntax, aber ich denke, Sie sollten * dies nicht als Teil des Add-Vorgangs zurückgeben. Behalten Sie stattdessen diese Instanz unverändert und geben Sie ein neues Objekt zurück, das den neuen Status enthält. bryanbcook vor 10 Jahren 0
`const float inches = 0.0` sollte` 0.0f` sein, andernfalls erfolgt eine implizite Konvertierung von `double 'in` float` John Dibling vor 10 Jahren 1
@john good catch hehe, ich dachte ursprünglich daran, es zu verdoppeln. greatwolf vor 10 Jahren 0
@bryan Das ist ein interessanter und gültiger Punkt, und ich kenne einige Sprachen, die diesen Ansatz verfolgen. Mein `Distance :: Add` ist wirklich ein verdeckter + = -Operator, und ich hätte das überladen können, aber es ist klar, dass das OP in C ++ noch relativ neu ist, sodass ich Verwirrung nicht vermeiden konnte. Wenn Sie in C ++ so etwas wie `int i = 0 machen; (i + = 42) ++; `, die zweite Anweisung erhöht 'i' nach dem Hinzufügen von 42. Ich wähle das nur, um dieses Verhalten mit der Distanz in Einklang zu bringen. greatwolf vor 10 Jahren 0
Ich würde mit $ 5 wetten, dass die Grader nach 'Add ()' suchen, um Zoll zu normalisieren, um im Bereich [0, 12) zu sein. Weitere hilfreiche Methoden sind `float getAsFeet () const {return feet + inches / 12.0f; } `und` float getAsInches () const {return 12.0f * feet + inches; } `. David Harkness vor 10 Jahren 0
Ich würde auch vorschlagen, dass Überlaufschutz obligatorisch sein sollte (z. B. wenn "feet" den Bereich von "INT_MAX" überschreitet, eine Ausnahme auslöst). Auch der Versuch, negative Werte für Fuß oder Zoll zu verwenden, sollte eine Ausnahme auslösen (Abstände können / sollten nicht negativ sein). Brendan vor 6 Jahren 0
Fügen Sie einfach ein Argument hinzu, warum Funktionsparameter für Werte im Allgemeinen nicht auf const gesetzt sind: Es fügt möglicherweise und unnötig Einschränkungen für eine Implementierung hinzu. Ihre aktuelle Implementierung ändert möglicherweise nicht die Eingabeparameter, eine zukünftige wird dies jedoch tun (aus welchem ​​Grund auch immer). Maikel vor 3 Jahren 0
9
DeadMG

Einige dieser Funktionen sollten Operatoren sein. Sie scheinen auch über den Zweck der Zugabe verwirrt zu sein. Ist auch using namespace stdschlecht. Sie haben auch keine anderen Operatoren angegeben. Auch wenn ein Klassenbenutzer logischerweise erwartet, dass Sie, wenn Sie eine Entfernung hinzufügen können, eine Entfernung zum aktuellen Objekt hinzufügen können und auch die Entfernungen subtrahieren können. Sie haben auch keine Eingabeverifizierung oder const-Korrektheit bereitgestellt.

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&);

Und die Implementierungen sind ...

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);
}
8

Es gibt keinen Grund, Zentimeter und Fuß zu haben, da der eine vom anderen berechnet werden kann. Überflüssige Redundanz erhöht die Komplexität.

Warum dies nicht der Top-Kommentar ist, übersteigt mich nicht. Obwohl es viele mögliche Verbesserungen gibt, wie in Vicors gute und durchdachte Antwort erwähnt, trifft dies den Nagel auf den Kopf. Was auch immer Sie tun, beheben Sie dies zuerst (und die Dinge werden viel einfacher). Martijn vor 10 Jahren 2
Vielleicht, weil der allererste Satz der Aufgabe besagte, dass die Klasse Füße und Zoll separat modellieren sollte. Ich habe vor langer Zeit gelernt, was die Aufgabe verlangt, es sei denn, ich weiß sicher, dass der Grader Optimierungen akzeptiert. David Harkness vor 10 Jahren 2
@David - der als Hausaufgabe zitierte Text sagt das nicht. vor 10 Jahren 0
@Crazy Eddie - Der erste Satz gibt speziell die Datentypen der beiden Attribute an: "Entwickeln Sie eine Klasse zum Messen der Entfernung als Fuß (sollte int sein), Zoll (sollte Float sein)." Der zweite Satz impliziert mindestens zwei Attribute unter Verwendung der Pluralform: "Include-Funktionen zum Setzen und Abrufen von Attributen." Ich weiß nicht, über welche anderen Attribute es sprechen würde. David Harkness vor 10 Jahren 1
5
Martin York

C ++ - Kommentare:

Initialisierungslisten bevorzugen:

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

Allgemeine Codierungskommentare:

Funktionalität nicht kombinieren:
Sie sollten eine Funktion definieren, um Distanzobjekte hinzuzufügen, und eine, um sie zu drucken. (DeadMG hat das oben abgedeckt).

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

Ich sehe auch, dass Sie Ihre Ergebnisse nicht normalisieren. Sie könnten 1 Fuß 300,05 Zoll haben. Wenn sich der Status eines Objekts ändert und ein Parameter in einen anderen übergeht, sollten Sie die Daten normalisieren. Verfügen Sie über eine explizite Funktion und rufen Sie sie bei jeder Statusänderung auf:

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

Implementierungskommentare:

Warum speichern Sie dann einen eigentlich einzigen Wert in zwei verschiedenen Variablen (Fuß und Zoll)? Warum speichern Sie nicht einfach die Gesamtdistanz in Zoll (und führen Sie dann eine Konvertierung auf dem Weg in / aus) durch. Schauen Sie sich die Unix-Zeit an. Es zählt nur die Sekunden seit der Epoche. Alle anderen Werte werden daraus berechnet.

2
xdev86

Ich bevorzuge auch, zuerst öffentliche Methoden zu schreiben, denn wenn Sie große Klassen durchsehen, müssen Sie zu öffentlichen Mitgliedern scrollen.

Zum Beispiel:

class MyClass
{
public:
// public members
protected:
// protected members
private:
// private members
}
0
Microsoft Developer

Sie hätten Methoden in der Klasse selbst implementieren können, in denen die Vorlage von Methoden definiert ist. Im Allgemeinen ist es eine gute Praxis, alle diese Methoden in der Klasse zu schreiben. Auch wenn Sie die Methoden außerhalb der Klasse geschrieben haben, wird der C ++ - Compiler zum Zeitpunkt der Kompilierung Inline erstellen. Daher ist es besser, diese Methoden als Inline-Methoden zu schreiben. Dadurch wird die Ausführung etwas schneller und die Verwendung des Bereichsauflösungsoperators wird aufgehoben, was scheinbar schwierig ist. Nachfolgend finden Sie das Beispiel zum Schreiben. Es enthält nur eine Methode, Sie können jedoch auch die restlichen Methoden verwenden.

#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;
}

Das ist der bessere Weg. Alle Klassenmethoden sollten nur in der Klasse definiert werden. Angenommen, Sie entwickeln nur eine Klasse in Java, dann können Sie keine gute Klasse entwickeln, indem Sie so schreiben.