7

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

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

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

谢谢你。

4

4 回答 4

3

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

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

  • 使用Base&(或Base*)句柄,您将拥有与以前完全相同的界面
  • 您可以完美地(如果您愿意)引入一个转发方法,并且无论如何直接public调用该方法:相同的效果与更多类型private
于 2013-05-21T11:34:34.323 回答
3

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

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

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

于 2013-05-21T11:40:28.820 回答
2

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

然而,“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++ 中可能导致您陷入陷阱的丑陋事物之一。

于 2013-05-21T12:04:14.703 回答
1

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

于 2013-05-21T11:24:14.053 回答