【问题标题】:C++ Constructor Parameters QuestionC++ 构造函数参数问题
【发布时间】:2011-02-27 20:10:18
【问题描述】:

我正在学习 C++。我有一个名为 GameContext 的简单类:

class GameContext {
    public:
        GameContext(World world);
        virtual ~GameContext();
};

要初始化一个GameContext 对象,我需要一个World 对象。

  • GameContext 构造函数是否应该采用 指针 指向 World 对象 (World*)、指向 World 对象 (&World) 的地址或 reference 到一个世界对象(World)?

  • 在参数附近使用const 关键字是什么?例如:GameContext(const World &world)

谢谢。

【问题讨论】:

    标签: c++ oop pointers constructor constants


    【解决方案1】:

    你的术语离题了。

    在 C++ 术语中,术语 pointeraddress 是同义词(就我们所讨论的值而言)。为了获取指针(或地址),您必须将参数声明为World* world

    要获取引用,参数应声明为World& world

    要获取复制值,参数应声明为World world

    您应该在每种特定情况下使用哪种声明取决于我们的意图。假设World 是一个重要的对象,选择通常应该限于引用World& world 或指针World* world

    如果您不打算在GameContext 的构造函数中修改源World 对象,则应添加constconst World& worldconst World* world

    最后,通过指针传递允许你传递一个“保留”值——一个空指针——但同时阻止你传递一个指向非左值的指针。如果这对您来说并不重要,那么您可能应该坚持使用参考 const World& world

    【讨论】:

    • “在 C++ 术语中,术语指针和地址是同义词”-> 我不同意。字节由地址标识,而对象由指针标识。请参阅标准中的 [basic.compound]。
    • @FredOverflow:在价值上下文中,文档交替使用术语 addresspointer。我没有看到任何对“字节”的限制。例如,参见一元 & 的描述。唯一可以坚持区分的情况是对象上下文:作为对象的指针通常不被称为“地址”,只有它们的值才是。
    • 参见 [intro.memory],它说“每个字节都有一个唯一的 地址。”而“一元 & 运算符的结果是一个指向其操作数的 指针。” [expr.unary.op] 但你是对的,因为大多数倾向于互换使用这些术语:)
    • @FredOverflow:不,恰恰相反,大多数人倾向于坚持区分,这在现实中并不存在。 [intro.memory] ​​并没有试图定义术语“地址”。 5.3.1 继续说““cv T”类型的对象的地址是“指向 cv T 的指针”。13.4 的标题是“重载函数的地址”,根据您对“地址”一词的解释,这完全没有意义”。再一次,在值上下文中,术语“指针”和“地址”在标准语言中是精确的同义词。
    【解决方案2】:

    首先,术语:World * 是指向 World 对象的指针是对的。但是,World & 将是对 World 对象的引用。 World 将是 World 对象的副本,而不是对其的引用。

    const(主要与指针或引用一起使用,如 World const &worldWorld const *world)意味着您正在获取指向 const 对象的引用/指针——换句话说,您不是允许修改它引用/指向的原始对象。

    对于小对象,您通常希望传递一个副本。对于大型对象,您通常需要传递一个 const 引用。这也有例外,但这是一个合理的经验法则,直到您了解了足够多的知识以知道何时违反规则(可以这么说)。

    仅根据名称,我猜您的 World 对象可能足够大,您可能希望通过 const 引用传递它,因此您的 ctor 应该如下所示:

    GameContext(World const &world);
    

    【讨论】:

      【解决方案3】:

      应该 GameContext 构造函数 获取指向 World 对象的指针 (World*),一个世界的地址 对象 (&World) 或对 a 的引用 世界对象(World)?

      首先,“World 对象的地址”与指向World 对象的指针是一回事。指针是一种存储对象地址的变量。如果你传递一个地址,那么你传递的地址对应的参数就是一个指针。

      是否要获取指针取决于World 类的语义。如果您获取一个值(而不是指针),那么您将收到传入的 World 对象的 副本。如果 GameContext 对象以外的其他对象需要对该 执行操作相同的 世界对象,那么您将需要传入并存储一个指针。如果这不是必需的,或者如果 World 类在内部运行,使得 World 对象的所有副本都使用一组公共数据,那么您可以按值传递。

      什么是const关键字使用时 靠近参数?例如: GameContext(const World &world)

      const 表示“无法修改”,就像它表示其他任何地方一样。正如您在示例中给出的那样,C++ 中的一个常见习惯是采用常量引用而不是采用值。当参数是一个对象(与intbool 等基本类型相反)时,这比取值更有效,因为在这种情况下不会进行复制。但是const 阻止函数修改引用的参数,所以对于调用者来说,它是一个引用并不重要。

      【讨论】:

        【解决方案4】:

        World 不是对World 对象的引用 - 编译器正在制作结构的副本并将其传递给堆栈。这很糟糕。

        指针 (World*) 和引用 (World&) 非常相似,它们仅在语法(->.)和范围(您不能分配引用,因此成员如果您使用引用,m_pWorld 在 GameContext 的生命周期内不能指向另一个世界 - 但如果您使用指针,则可以这样做)。我的建议是,如果您(可能)总是使用同一个 World,请获取参考,否则请使用指针。

        const 告诉编译器你不会修改对象。当您获得对对象的引用时,您正在处理 对象,而不是它的副本 - 因此您在方法中修改的任何内容实际上都会修改“外部”对象。在您的情况下,由于您可能会在 GameContext 中修改或以其他方式操作您的 World,因此您可能需要一个非常量引用。

        所以你应该这样做

        class GameContext 
        {
        public:
            GameContext (World& pWorld) : m_pWorld(pWorld)
            {
            }
        
            virtual ~GameContext () { ... }
        
            void foo (int nParam)
            {
                m_pWorld.bar(nParam);
            }
        
        private:
            World& m_pWorld;
        };
        

        【讨论】:

          【解决方案5】:

          const表示方法GameContext不能修改参数world的内容

          【讨论】:

            【解决方案6】:

            引用比指针更安全,并且不涉及复制。至于 const 关键字,请阅读我前段时间提出的这个问题的答案:How many and which are the uses of "const" in C++?

            【讨论】:

              【解决方案7】:

              理想情况下,您应该接受constWorld 的引用:

              class GameContext {
                  public:
                      GameContext(const World& world);
                      virtual ~GameContext();
              };
              

              首先,这样在传递world 时不会发生复制。其次,const 是关键字,这意味着您不会更改传递的参数,在这种情况下是 world

              【讨论】:

              • 我同意。这是要走的路。
              • 谢谢,那你这样称呼它:World world; GameContext context(world);?
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-08-23
              • 1970-01-01
              • 1970-01-01
              • 2010-10-21
              • 1970-01-01
              相关资源
              最近更新 更多