overriding with difference access specification c+

2020-02-07 01:46发布

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 overriding these abstract methods but with protected/public access specifier.

I never came across such thing where overridden methods in derived class had different access specification. Is this allowed ? If yes, does it comply to "IS A" relation between base and derived (i.e. safely substitutable).

Could you point me to some references which can provide more details on such usages of classes ?

Thank you.

标签: c++
4条回答
爷的心禁止访问
2楼-- · 2020-02-07 02:04

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.

查看更多
Fickle 薄情
3楼-- · 2020-02-07 02:09

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.

查看更多
Animai°情兽
4楼-- · 2020-02-07 02:13

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
查看更多
够拽才男人
5楼-- · 2020-02-07 02:21

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.

查看更多
登录 后发表回答