Waar plaats ik constanten die mijn klas nodig heeft om de wereldwijde ruimte vrij te houden?

Ten eerste: ik weet hoe ik het programma moet schrijven, dus ik vraag hier geen hulp voor. Ik plak echter een kopie van het probleem zodat je kunt zien wat de opdracht inhoudt. Mijn vraag is specifiek gericht op waar plaats je variabelen om te voorkomen dat je alles wereldwijd maakt?

Opdracht

Ontwerp een klasse met de naam Date met gehele gegevensleden om maand, dag en jaar op te slaan. De klasse moet een constructor met drie parameters hebben waarmee de datum kan worden ingesteld op het moment dat een nieuw object Date wordt gemaakt. Als de gebruiker een object Date maakt zonder argumenten door te geven of als een van de doorgegeven waarden ongeldig is, moeten de standaardwaarden van 1, 1, 2001 (d.w.z. 1 januari 2001) worden gebruikt. De klasse moet lidfuncties hebben om de datum in de volgende indelingen af ​​te drukken:

3/15/10
March 15, 2010
15 March 2010

Vraag

1) De leraar heeft ons geïnstrueerd om magische nummers in onze code te vermijden, dus de eerste vraag betreft mijn implementatie van de standaardconstructor:

// These are outside the class.
#define DEFAULT_MONTH 1
#define DEFAULT_DAY   1
#define DEFAULT_YEAR  2001

// This is inside the class definition.
Date(int month = DEFAULT_MONTH, int day = DEFAULT_DAY, int year = DEFAULT_YEAR);

Is dit correct?

2) De klasse heeft toegang nodig tot een array van string -objecten die de maandnamen bevatten, zodat ik ze kan gebruiken voor datumuitvoer waarbij de maandnaam wordt weergegeven in plaats van het maandnummer. Ik heb een enum gebruikt voor de numerieke maand (die wordt gebruikt voor de -schakelaar ).

const enum MONTH_IDS { JANUARY = 1, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY,
    AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER };

const string MONTH_NAMES[NUM_MONTHS] = { "January", "February", "March",
    "April", "May", "June", "July", "August", "September", "October",
    "November", "December" };

De vraag voor dit deel is, waar plaatst u ze?

Some things I can't do... I am not allowed to use static class members yet because that will be covered in the next chapter. We also have not gone over pointers, but we can use references.

Bedankt voor je hulp!

Ik zou de instructeur vragen, maar hij is de stad uit en de opdracht moet morgen in zijn bezit zijn.

5
Mag je statische lokale variabelen gebruiken?
toegevoegd de auteur Robᵩ, de bron
Geen statische leden, maar statische locals. Zie mijn aanstaande antwoord.
toegevoegd de auteur Robᵩ, de bron
U kunt de constanten onder een naamruimte plaatsen. Constants :: MY_CONST; of iets zoals dit.
toegevoegd de auteur FailedDev, de bron
@Rob Ik ben me bewust van statische leden, maar ik kan ze niet gebruiken tot hoofdstuk 9.
toegevoegd de auteur user898058, de bron
@FailedDev Ik dacht dat dit misschien ook de beste manier was om te gaan.
toegevoegd de auteur user898058, de bron

3 antwoord

1) Definities zijn lelijk. static const int leden zijn wat ik zou doen, maar je kunt niet ... Wat vind je van enums?

struct Date {
    enum Constants {
        DEFAULT_YEAR = 2001,
        DEFAULT_MONTH = 1,
        DEFAULT_DAY = 1,
    };


    Date(int month = DEFAULT_MONTH, int day = DEFAULT_DAY, int year = DEFAULT_YEAR);

};

2) Een array met statische leden is precies wat u nodig hebt. Maar aangezien u geen ... statische lokale variabelen kunt:

struct Date {
    std::string MonthToString(enum MONTH_IDS m) {
        static const char *monthNames[] = {
            "January", "February", "March", "April", "May", "June",
            "July", "August", "September", "October", "November", "December" };
        if(m >= sizeof(monthNames)/sizeof(monthNames[0]))
            return std::string("Unknown");
        return std::string(monthNames[m]);
    }
};
4
toegevoegd
@ephaitch: zie voorbeeld # 2 in mijn antwoord. De variabele monthNames is een statische lokale variabele.
toegevoegd de auteur Robᵩ, de bron
Wilt u een voorbeeld geven van hoe u statische lokale variabelen zou implementeren? Zou je ze zelf in de constructor stoppen? of in een lidfunctie die door de constructor wordt geroepen? Of een geheel andere implementatie.
toegevoegd de auteur user898058, de bron
oeps .. Ik keek ernaar en realiseerde me dat MonthToString een functie was. Bedankt!
toegevoegd de auteur user898058, de bron

Als u een constante wilt definiëren zonder een globale naamruimte te vervuilen, zijn twee van uw beste opties namen met een namespace of klassestatistieken. Aangezien u zegt dat u klassestatistieken niet kunt gebruiken, laat ik een voorbeeld van naamgeschillen globaal zien:

// .h file
namespace mynamespace {
    extern const int foo;
};

// later, in a .cpp file
namespace mynamespace {
    const int foo = 42;
};

Je hebt toegang tot deze variabele als mynamespace :: foo , of door met namespace mynamespace; (die moet worden vermeden in header-bestanden), of als alleen foo in een andere functie in de naamruimte mynamespace . Omdat het alleen toegankelijk is door iets dat de naamruimte mynamespace vraagt ​​(of anderszins kent), voorkomt het het vervuilen van de globale naamruimte (en alle ongelukkige naambotsingen die dit met zich meebrengt).

Voor numerieke waarden is een opsomming een andere keuze:

class foo {
  enum { CONST_FOO = 42, CONST_BAR = 24 };
};

Deze waarden zijn compilatietijdconstanten; u kunt niet het adres van hen nemen (maar ze kunnen een beetje sneller zijn dan const variabelen). Merk op dat dit alleen kan worden gebruikt voor gehele getallen.

Functie statica is een andere goede optie:

void myclass::somefunction() {
    static const char *monthNames[] = { "JANUARY", ... };
    //...
}

Omdat de array echter diep in uw implementatie is ingebed, is deze niet veel beter dan een 'magisch nummer'.

In jouw geval denk ik dat het gebruik van enum s of (voor niet-gehele getallen) class-statics het beste zou zijn. Als je docent het gebruik van klassestatistieken willekeurig heeft beperkt, plaats je de variabelen op globaal bereik (mogelijk in een naamruimte) en voeg je een opmerking toe waarin staat dat je deze class-statics zou hebben gemaakt als dat was toegestaan.

2
toegevoegd
Bedankt voor de gedetailleerde uitleg!
toegevoegd de auteur user898058, de bron

Als je static const members (of locals) niet kunt doen, kun je alles in een namespace plaatsen:

verklaring:

namespace ephaitch {
    extern const int Date_default_month;
    extern const int Date_default_day;
    extern const int Date_default_year;
    class Date {
        Date(int month = DEFAULT_MONTH, int day = DEFAULT_DAY, int year = DEFAULT_YEAR);
    };
}

definitie:

namespace ephaitch {
    const int Date_default_month = 1;
    const int Date_default_day = 1;
    const int Date_default_year = 2001; 

    enum MONTH_IDS { JANUARY = 1, FEBRUARY, MARCH, APRIL, 
                     MAY, JUNE, JULY, AUGUST, 
                     SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER 
                   };

    const string MONTH_NAMES[NUM_MONTHS] = { 
         "January", "February", "March",
         "April", "May", "June", 
         "July", "August", "September", 
         "October", "November", "December" 
        };

    Date(int month, int day, int year)
    {
    }
}

Gebruik geen DEFINE s, ze vervuilen alle naamruimten en maken het debuggen lastiger. enum s zijn beter, maar omdat dat niet het bedoelde gebruik is, kan het verwarrend zijn.

0
toegevoegd