C++ C++;样式:为重写的方法添加虚拟关键字前缀

C++ C++;样式:为重写的方法添加虚拟关键字前缀,c++,methods,coding-style,virtual-functions,C++,Methods,Coding Style,Virtual Functions,我一直在与同事讨论是否使用virtual关键字作为重写方法的前缀,还是仅在原始基类中使用 我倾向于在所有虚拟方法(即涉及vtable查找的方法)前面加上virtual关键字。我的理由有三: >P>假定C++没有重写 关键字,虚拟机的存在 关键字至少会通知您 该方法包括查找和 理论上可以被 进一步的专业化,或者可以 通过指向更高级别的指针调用 基类 坚持使用这种风格 也就是说,当你看到一个方法 (至少在我们的代码范围内)没有 虚拟关键字,你可以 最初假设两者都不是 源于基础或特殊的 在子类中 如

我一直在与同事讨论是否使用virtual关键字作为重写方法的前缀,还是仅在原始基类中使用

我倾向于在所有虚拟方法(即涉及vtable查找的方法)前面加上virtual关键字。我的理由有三:

>P>假定C++没有重写 关键字,虚拟机的存在 关键字至少会通知您 该方法包括查找和 理论上可以被 进一步的专业化,或者可以 通过指向更高级别的指针调用 基类

  • 坚持使用这种风格 也就是说,当你看到一个方法 (至少在我们的代码范围内)没有 虚拟关键字,你可以 最初假设两者都不是 源于基础或特殊的 在子类中

  • 如果由于某些错误 已从IFoo中删除虚拟对象,所有 儿童仍将发挥作用 (cFoosSpecialization::多巴会 仍然覆盖CFooBase::DoBar, 而不是简单地隐藏它)

  • 据我所知,反对这种做法的理由是,“但这种方法不是虚拟的”(我认为这是无效的,是由于对虚拟性的误解造成的),以及“当我看到虚拟关键词时,我希望这意味着有人是从中派生出来的,并去寻找它们。”

    假设类可能分布在几个文件中,并且有几个专门化

    class IFoo {
    public:
        virtual void DoBar() = 0;
        void DoBaz();
    };
    
    class CFooBase : public IFoo {
    public:
        virtual void DoBar(); // Default implementation
        void DoZap();
    };
    
    
    class CFooSpecialization : public CFooBase {
    public:
        virtual void DoBar(); // Specialized implementation
    };
    

    在风格上,您会从两个派生类中删除virtual关键字吗?若然,原因为何?Stack Overflow的想法是什么?

    我完全同意你的观点。这是一个很好的提醒,方法在调用时将具有动态分派语义。你的同事使用的“该方法不是虚拟的”论点完全是假的。他混淆了虚拟和纯虚拟的概念。

    我倾向于不使用编译器允许我省略的任何语法。话虽如此,C#(试图超越C++)设计的一部分是要求虚拟方法的重写标记为“重写”,这似乎是一个合理的想法。我担心的是,由于它是完全可选的,因此有人忽略它只是时间问题,到那时,您已经养成了期望覆盖被指定为“虚拟”的习惯。那么,也许最好是生活在语言的限制之内。

    添加
    virtual
    对任何一种方式都没有重大影响。我倾向于喜欢,但这确实是一个主观问题。但是,如果您确保使用,那么在编译时捕获错误的能力将得到显著的提高

    我的PCH中包含以下行:

    #if _MSC_VER >= 1400
    #define OVERRIDE override
    #define SEALED sealed
    #else
    #define OVERRIDE
    #define SEALED
    #endif
    
    一个函数一旦成为虚拟函数,就始终是虚拟函数

    因此,在任何情况下,如果在后续类中未使用virtual关键字,则不会阻止函数/方法成为“virtual”,即被重写。因此,我参与的其中一个项目有以下我有点喜欢的指导方针:

    • 如果函数/方法被假定为 始终使用 “虚拟”关键字。这尤其重要 在接口/基础中使用时为true 上课
    • 如果派生类应该 进一步明确地划分为子类 为每个项目声明“virtual”关键字 可以使用的函数/方法 被推翻。C++11使用“override”关键字
    • 如果派生函数中的函数/方法 课堂不应该是这样的 再次子类,然后是关键字 “虚拟”将被注释 表示函数/方法 已被重写,但没有 覆盖它的其他类 再一次。当然,这并不能阻止 有人阻止他在 派生类,除非 是最终的(不可派生),但 指示不应使用该方法 被推翻。 例如:
      /*virtual*/void guiFocusEvent()
      C++11,使用'final'关键字和'override'
      例如:
      void guiFocusEvent()覆盖final

      • 我可以想到一个缺点:
        当一个类成员函数未被重写并且声明为虚拟时,您将在该类定义的虚拟表中添加一个不必要的条目。

        注意:我的回答涉及到C++03,我们中的一些人仍然在使用它。C++11具有@JustinTime在注释中建议的
        覆盖
        最终
        关键字,可能应该使用这些关键字来代替以下建议

        已经有很多答案,其中最突出的是两种相反的观点。我想把@280Z28在回答中提到的内容与@StevenSudit的观点和@Abhay的风格指南结合起来

        我不同意@280Z28,也不会使用微软的语言扩展,除非你确定你只会在Windows上使用该代码

        但我确实喜欢这些关键词。那么,为什么不直接使用define-d关键字来增加清晰度呢

        #define OVERRIDE
        #define SEALED
        

        不同之处在于,在第三点中概述的情况下,您决定要发生什么

        3-如果由于某种错误,虚拟对象被从IFoo中删除,那么所有子对象仍将正常工作(CFooSpecialization::DoBar仍将覆盖CFooBase::DoBar,而不是简单地隐藏它)

        虽然我认为这是一个编程错误,因此没有“修复”,您甚至不应该费心减轻它,但应该确保它崩溃或以其他方式通知程序员(尽管我现在想不出一个)

        如果您选择了第一个选项并且不喜欢添加
        #define
        ,那么您可以使用如下注释:

        /* override */
        /* sealed */
        

        <> P>这应该对所有你想要的强>清晰/强]的情况做,因为我不认为“虚拟”这个词足够清楚你想要它做什么。

        我想看看Bjarne(或C++委员会)为什么要在派生类中省略虚拟。理由可能是
        /* override */
        /* sealed */