overriding with difference access specification c++

后端 未结 4 1837

I came across a question while taking iKM test. There was a base class with two abstract methods with private access specifier. There was a derived class which was overridin

相关标签:
4条回答
  • 2020-12-11 18:16

    Yes, this is legal, accessibility is checked statically (not dynamically):

    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);
    }
    

    Now, why would you want to do that? It only matters if you use the derived class B directly (2nd param of f()) as opposed to through the base A interface (1st param of f()). If you always use the abstract A interface (as I would recommend in general), it still complies to the "IS-A" relashionship.

    0 讨论(0)
  • 2020-12-11 18:17

    Yes, this is allowed as long as the signature is the same. And in my opinion, yes, you're right, overriding visibility (for example, public -> private) breaks IS-A. I believe Scott Myers Effective C++ series has a discussion on this one.

    0 讨论(0)
  • 2020-12-11 18:27

    As many of the guys pointed out it is legal.

    However, "IS-A" part is not that simple. When it comes to "dynamic polymorphism" "IS-A" relation holds, I.e. everything you can do with Super you can also do with Derived instance.

    However, in C++ we also have something that is often referred as static polymorphism (templates, most of the time). Consider the following example:

    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();
    }
    

    Now, when you try to use "dynamic polymorphism" everything seems to be ok:

    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
    

    ... but when you use "static polymorphism" you can say that "IS-A" relation no longer holds:

    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
    

    So, in the end, changing visibility for method is "rather legal" but that's one of the ugly things in C++ that may lead you to pitfall.

    0 讨论(0)
  • 2020-12-11 18:27

    It is allowed, in both directions (ie, from private to public AND from public to private).

    On the other hand, I would argue it does not break the IS-A relationship. I base my argument on 2 facts:

    • using a Base& (or Base*) handle, you have exactly the same interface as before
    • you could perfectly (if you wish) introduce a forward method that is public and calling the private method directly anyway: same effect with more typing
    0 讨论(0)
提交回复
热议问题