在C ++中,有没有理由不通过类实例访问静态成员变量?我知道Java对此皱眉,并想知道它是否在C ++中很重要。例如:
class Foo {
static const int ZERO = 0;
static const int ONE = 1;
...
};
void bar(const Foo& inst) {
// is this ok?
int val1 = inst.ZERO;
// or should I prefer:
int val2 = Foo::ZERO
...
};
我有第二个问题。如果我声明一个静态double,我必须在某处定义它,并且该定义必须重复该类型。为什么必须重复这种类型? 例如:
In a header:
class Foo {
static const double d;
};
In a source file:
const double Foo::d = 42;
为什么我必须在cpp文件中重复“const double”部分?
答案 0 :(得分:6)
我希望Foo::ZERO
超过inst.ZERO
,因为它更清楚地告诉我们发生了什么。但是,在类Foo
的方法中,我只使用ZERO
。
至于奖金问题,const
只是完整类型的一部分。
答案 1 :(得分:5)
对于第一个问题,除了风格问题(它显然它是一个类变量并且没有相关对象),Fred Larsen在对问题的评论中提到了前一个问题。请阅读Adam Rosenthal's answer以了解非常为什么要小心这一点。 (如果弗雷德将其作为答案发布,我会对其进行投票,但我不能相信它应该归还的地方。我向亚当投票了。)
至于你的第二个问题:
为什么我必须在cpp文件中重复“const double”部分?
您必须首先重复该类型作为实现细节:它是C ++编译器解析声明的方式。这对于局部变量也不是非常理想的,并且C ++ 1x(以前的C ++ 0x)使用auto
关键字来避免需要对常规函数变量重复。
所以这个:
vector<string> v;
vector<string>::iterator it = v.begin();
可以成为:
vector<string> v;
auto it = v.begin();
没有明确的理由说明为什么这也不适用于静态,所以在你的情况下thos:
const double Foo::d = 42;
很可能成为这个。
static Foo::d = 42;
关键是要有一些方式将其识别为声明。
注意我说没有清除原因:C ++的语法是一个活生生的传说:非常很难涵盖所有边缘情况。我不认为以上是模棱两可的,但可能是。如果不是,他们可以将其添加到语言中。告诉他们...对于C ++ 2x:/。
答案 2 :(得分:3)
鉴于你将它们声明为静态并使它们成为类常量,我会使用Foo :: Zero将意图传达给随意而不那么随意的代码读者。
我还会替换常量的全部大写名称,即将Foo :: ZERO转换为Foo :: Zero。预处理程序宏的常规约定是将它们全部用大写命名,并且对C ++常量使用类似的命名方案会遇到麻烦,因为预处理程序可能会对您的C ++常量进行调整,最终会得到非常有趣的错误消息。
答案 3 :(得分:1)
我会使用Foo :: ZERO,但那只是我。特别是如果你来自Foo,那会让人感到困惑。
对于第二个问题,您需要为double值创建内存,这在实现单元中发生。
我认为你不需要创建内存的唯一类型是const整数类型。然后,您可以将值放在头文件中。但由于它没有地址,因此除非将定义放在.cpp文件中,否则无法通过引用函数来传递它。 (这似乎是它与gcc一起使用的方式)。
答案 4 :(得分:1)
您在示例中使用哪种形式无关紧要。它们都意味着同样的事情。我更喜欢一般使用类方法,因为你可能并不总是有一个实例方便使用点运算符。
如果你考虑有人写一个模板函数,那么有两个选项是很好的。他们可能用点运算符编写了函数。具有静态类成员的类仍可用于实例化模板,因为支持该语法。
至于你的奖金问题,这就是语言的方式。您始终必须声明完整类型。你应该在一个单独的问题中提出这个问题。
答案 5 :(得分:1)
我亲自使用匿名枚举。尽管最终结果完全相同:)
至于你的问题。我肯定更喜欢Foo :: Zero,因为通过查看它所访问的内容显而易见。 inst.Zero要求你事先弄清楚什么类型的inst。
您必须重复数据类型,因为这就是C ++的工作原理。如果您在头文件中编写以下内容,则采用相同的方式。
extern int foo;
您仍需要提及
int foo
在CPP文件中。正如pukku提到的那样,你声明了一个类型为“const int”的变量。因此,必须在变量的定义中重复“const int”。