我在参加 iKM 测试时遇到了一个问题。有一个基类,其中包含两个带有私有访问说明符的抽象方法。有一个派生类覆盖了这些抽象方法,但具有受保护/公共访问说明符。
我从未遇到过派生类中的重写方法具有不同访问规范的情况。这是允许的吗?如果是,它是否符合基础和派生之间的“IS A”关系(即安全可替代)。
您能否指出一些可以提供有关此类用法的更多详细信息的参考资料?
谢谢你。
我在参加 iKM 测试时遇到了一个问题。有一个基类,其中包含两个带有私有访问说明符的抽象方法。有一个派生类覆盖了这些抽象方法,但具有受保护/公共访问说明符。
我从未遇到过派生类中的重写方法具有不同访问规范的情况。这是允许的吗?如果是,它是否符合基础和派生之间的“IS A”关系(即安全可替代)。
您能否指出一些可以提供有关此类用法的更多详细信息的参考资料?
谢谢你。
在两个方向上都是允许的(即,从private
到public
和从public
到private
)。
另一方面,我认为它不会破坏 IS-A 关系。我的论点基于两个事实:
Base&
(或Base*
)句柄,您将拥有与以前完全相同的界面public
调用该方法:相同的效果与更多类型private
是的,这是合法的,可访问性是静态检查的(不是动态的):
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”的关系。
正如许多人指出的那样,这是合法的。
然而,“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++ 中可能导致您陷入陷阱的丑陋事物之一。
是的,只要签名相同,这是允许的。在我看来,是的,你是对的,压倒一切的可见性(例如,公共 -> 私人)会破坏 IS-A。我相信 Scott Myers Effective C++ 系列对此有一个讨论。