我该把类所需的常量放在哪里,以保持全局空间不被占用?

5

首先:我知道如何编写程序,所以我并不需要在这方面寻求帮助。然而,我会把问题的副本粘贴在下面,以便您了解作业的要求。我的问题是针对如何避免使一切都变成全局变量而提出的。

作业

设计一个名为Date的类,具有存储月、日和年的整数数据成员。该类应该有一个三参数默认构造函数,允许在创建新的日期对象时设置日期。如果用户创建了一个没有传递任何参数的Date对象,或者传递的任何值无效,则应该使用默认值1、1、2001(即2001年1月1日)。该类应该有成员函数以以下格式打印日期:

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

问题

1)老师已指示我们在代码中避免使用魔术数字,因此第一个问题涉及我对默认构造函数的实现:

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

这样正确吗?

2)该类需要访问一个string对象数组,其中包含月份名称,以便我可以将其用于显示月份名称而不是月份数的日期输出。我使用了一个数字月份的enum(将用于switch)。

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

这部分的问题是,你把它们放在哪里? 一些我不能做的事情... 我还不允许使用静态类成员,因为那将在下一章中介绍。我们也没有讲解指针,但我们可以使用引用。
感谢您的帮助! 我想问问老师,但他不在城里,而且作业明天就要交了。

1
你可以将常量放在命名空间下。Constants::MY_CONST; 或者类似这样的方式。 - FailedDev
你可以使用静态局部变量吗? - Robᵩ
@Rob 我知道静态成员,但在第9章之前我不能使用它们。 - user898058
@FailedDev 我也在想这可能是最好的方法。 - user898058
不是静态成员,而是静态局部变量。请看我的回答。 - Robᵩ
3个回答

4

1) 宏定义很丑。我会使用 static const int 成员变量,但你不能...那么枚举如何?

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) 静态成员数组正是您所需的。但由于您无法…也许可以考虑使用静态局部变量:

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

您能否提供一个实现静态局部变量的例子?您会将它们放在构造函数本身中吗?还是放在由构造函数调用的成员函数中?或者采用完全不同的实现方式。 - user898058
@ephaitch:请参考我的回答中的第二个示例。变量monthNames是一个静态局部变量。 - Robᵩ
糟糕..我再次查看后发现MonthToString是一个函数。谢谢! - user898058

2
如果你想定义一个常量而不会污染全局命名空间,最好的两个选项是使用命名空间全局变量或类静态。由于你说你不能使用类静态,我将展示一个命名空间全局变量的例子:
// .h file
namespace mynamespace {
    extern const int foo;
};

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

您可以通过mynamespace::foo访问此变量,或通过using namespace mynamespace;(在头文件中应避免使用),或在mynamespace名称空间中的任何其他函数中仅使用foo。由于它只能被请求(或以其他方式知道)mynamespace名称空间的内容所访问,因此避免了污染全局命名空间(以及所有不幸的名称冲突)。对于数字值,enum是另一种选择:
class foo {
  enum { CONST_FOO = 42, CONST_BAR = 24 };
};

这些值是编译时常量,您无法获取它们的地址(但它们可能比const变量更快)。请注意,这仅适用于整数值。

函数静态变量是另一个不错的选择:

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

然而,由于数组深嵌入您的实现中,所以它并不比“魔法数字”更好。

在您的情况下,我认为最好使用enum或(对于非整数)类静态变量。如果您的教授任意限制了类静态变量的使用,请将变量放在全局范围内(可能在命名空间中),并添加注释说明如果允许,您会将它们设置为类静态变量。


0
如果您无法使用static const成员(或局部变量),您可以将所有内容放入命名空间中:

声明:

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

定义:

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)
    {
    }
}

不要使用DEFINE,它们会污染所有命名空间,并使调试更加棘手。enum更好,但由于这不是预期的用法,可能会令人困惑。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接