【问题标题】:C++: access const member vars through class or an instance?C++:通过类或实例访问 const 成员变量?
【发布时间】:2009-08-06 20:07:38
【问题描述】:

在 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
   ...
};

我有一个额外的第二个问题。如果我声明一个静态双精度,我必须在某处定义它,并且该定义必须重复该类型。为什么必须重复类型? 例如:

In a header:
  class Foo {
    static const double d;
  };
In a source file:
  const double Foo::d = 42;

为什么我必须在我的 cpp 文件中重复“const double”部分?

【问题讨论】:

  • 不是完全重复,但我认为可能适用相同的答案:stackoverflow.com/questions/840522/…
  • 是的。阅读 Adam Rosenthal 的回答,了解为什么您应该更喜欢将类作为前缀而不是实例的充分理由。

标签: c++ static constants


【解决方案1】:

我更喜欢Foo::ZERO 而不是inst.ZERO,因为它更清楚地说明了正在发生的事情。但是,在 Foo 类的方法中,我只会使用 ZERO。

至于附加问题,const 只是完整类型的一部分。

【讨论】:

  • 我知道 const 是类型的一部分。我想知道为什么我必须重复这种类型。我只想说: Foo::d = 42;头文件中只声明了一个 Foo::d 。这是否会引入一些我在这里没有看到的模棱两可的可能性?是否有名为 d 的成员函数?我知道重复该类型是有充分理由的,但我只是不知道那是什么。
  • 也许这只是语言的规则?
  • 我试图在评论中解释这一点,但空间不足(叹气)。我在下面回答。
【解决方案2】:

对于第一个问题,除了样式问题(很明显它是一个类变量并且没有关联的对象)之外,Fred Larsen 在问题的 cmets 中引用了上一个问题。阅读Adam Rosenthal's answer 了解非常为什么你要小心这一点的充分理由。 (如果 Fred 将其发布为答案,我会投票赞成,但我不能相信它应该在哪里。我确实投票赞成 Adam。)

关于你的第二个问题:

为什么我必须在我的 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();

没有明确的原因为什么这也不能与静态一起使用,所以在你的情况下:

const double Foo::d = 42;

很可能会变成这样。

static Foo::d = 42;

关键是要有一些方法来将其识别为声明。

请注意,我说没有明确原因:C++ 的语法是一个活生生的传奇:非常很难涵盖所有边缘情况。我不认为以上是模棱两可的,但它可能是。如果不是,他们可以将其添加到语言中。告诉他们...对于 C++2x :/.

【讨论】:

    【解决方案3】:

    鉴于您将它们声明为静态并使其成为类常量,我将使用 Foo::Zero 将意图传达给您的代码的随意而不是随意的读者。

    我还将替换所有大写的常量名称,即将 Foo::ZERO 转换为 Foo::Zero。预处理器宏的常规约定是将它们全部命名为大写,并且为 C++ 常量使用类似的命名方案会带来麻烦,因为预处理器可能只会对 C++ 常量进行吹嘘,最终会得到非常有趣的错误消息。

    【讨论】:

    • 哇——关于命名约定的好点。实际上,我不止一次被这个问题所困扰(请大家停止#define'ing PI!!!)
    【解决方案4】:

    我会使用 Foo::ZERO,但这只是我。特别是如果您从 Foo 派生,这会让人感到困惑。

    对于第二个问题,您需要为双精度值创建内存,这发生在实现单元中。

    我认为您不需要为其创建内存的唯一类型是 const 整数类型。然后,您可以将值放入头文件中。但是由于它没有地址,因此您无法通过引用函数来传递它,除非您将定义放在 .cpp 文件中。 (这似乎是它与 gcc 一起工作的方式)。

    【讨论】:

      【解决方案5】:

      在您的示例中使用哪种形式并不重要。他们俩的意思是一样的。一般来说,我更喜欢使用类方式,因为您可能并不总是有一个方便使用点运算符的实例。

      如果您考虑有人编写模板函数,那么同时拥有这两种选择是很好的。他们可能已经使用点运算符对函数进行了编码。您的具有静态类成员的类仍可用于实例化模板,因为支持该语法。

      至于你的额外问题,语言就是这样。你总是必须声明完整的类型。您可能应该在一个单独的问题中提出这个问题。

      【讨论】:

        【解决方案6】:

        我个人会使用匿名枚举。最终结果是完全一样的:)

        至于你的问题。我绝对更喜欢 Foo::Zero,因为从您正在访问的内容中可以明显看出它。 inst.Zero 要求您事先弄清楚 inst 是什么类型。

        您必须重复数据类型,因为这就是 C++ 的工作方式。如果您在头文件中写入以下内容,则以同样的方式。

        extern int foo;
        

        您仍然需要提及

        int foo
        

        在 CPP 文件中。正如 pukku 提到的,您正在声明一个“const int”类型的变量。因此,“const int”必须在变量的定义中重复。

        【讨论】:

        • 匿名枚举强制特定的存储大小 (int)。如果您希望常量具有不同的类型,则不能使用匿名枚举。
        猜你喜欢
        • 2014-04-18
        • 1970-01-01
        • 2020-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多