【问题标题】:overriding with difference access specification c++用差异访问规范覆盖 C++
【发布时间】:2018-09-18 16:45:37
【问题描述】:

我在参加 iKM 测试时遇到了一个问题。有一个基类,其中包含两个带有私有访问说明符的抽象方法。有一个派生类覆盖了这些抽象方法,但具有受保护/公共访问说明符。

我从未遇到过派生类中的重写方法具有不同访问规范的情况。这是允许的吗?如果是,它是否符合基础和派生之间的“IS A”关系(即安全可替代)。

您能否指出一些可以提供有关此类用法的更多详细信息的参考资料?

谢谢。

【问题讨论】:

    标签: c++


    【解决方案1】:

    在两个方向上都是允许的(即从privatepublic 和从publicprivate)。

    另一方面,我认为它不会破坏 IS-A 关系。我的论点基于两个事实:

    • 使用Base&(或Base*)句柄,您将拥有与以前完全相同的界面
    • 您可以完美地(如果您愿意)引入 public 的转发方法并直接调用 private 方法:同样的效果与更多的输入

    【讨论】:

      【解决方案2】:

      是的,这是合法的,可访问性是静态检查的(不是动态的):

      class A {
      public:
          virtual void foo() = 0;
      private:
          virtual void bar() = 0;
      };
      
      class B : public A {
      private:
          virtual void foo() {} // public in base, private in derived
      public:
          virtual void bar() {} // private in base, public in derived
      };
      
      void f(A& a, B& b)
      {
          a.foo(); // ok
          b.foo(); // error: B::foo is private
          a.bar(); // error: A::bar is private
          b.bar(); // ok (B::bar is public, even though A::bar is private)
      }
      
      int main()
      {
          B b;
          f(b, b);
      }
      

      现在,您为什么要这样做?仅当您直接使用派生类Bf() 的第二个参数)而不是通过基类A 接口(@98​​7654325@ 的第一个参数)时才重要。 如果你总是使用抽象的A 接口(我通常会推荐),它仍然符合“IS-A”关系。

      【讨论】:

        【解决方案3】:

        正如许多人指出的那样,这是合法的。

        但是,“IS-A”部分并不是那么简单。当谈到“动态多态性”时,“IS-A”关系成立,即你可以用 Super 做的所有事情,你也可以用 Derived 实例做。

        然而,在 C++ 中,我们也有一些通常被称为静态多态性的东西(大多数时候是模板)。考虑以下示例:

        class A {
        public:
            virtual int m() {
                return 1;
            }
        };
        
        class B : public A {
        private:
            virtual int m() {
                return 2;
            }
        };
        
        template<typename T>
        int fun(T* obj) {
            return obj->m();
        }
        

        现在,当您尝试使用“动态多态性”时,一切似乎都正常:

        A* a = new A();
        B* b = new B();
        
        // dynamic polymorphism
        std::cout << a->m(); // ok
        std::cout << dynamic_cast<A*>(b)->m(); // ok - B instance conforms A interface
        // std::cout << b->m(); fails to compile due to overriden visibility - expected since technically does not violate IS-A relationship
        

        ...但是当您使用“静态多态性”时,您可以说“IS-A”关系不再成立:

        A* a = new A();
        B* b = new B();
        
        // static polymorphism
        std::cout << fun(a); // ok
        //std::cout << fun(b); // fails to compile - B instance does not conform A interface at compile time
        

        因此,最后,更改方法的可见性是“相当合法的”,但这是 C++ 中的丑陋事物之一,可能会导致您陷入陷阱。

        【讨论】:

          【解决方案4】:

          是的,只要签名相同,这是允许的。 在我看来,是的,你是对的,覆盖可见性(例如,公共 -> 私有)会破坏 IS-A。我相信 Scott Myers Effective C++ 系列对此有一个讨论。

          【讨论】:

          猜你喜欢
          • 2019-12-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多