Java中不允许这样做:
class A {
public void method() {}
}
class B extends A {
private void method() {}
}
它会生成编译错误:
error: method() in B cannot override method() in A
attempting to assign weaker access privileges; was public
但是,这在C ++中是允许的:
class A {
public:
virtual void method() {}
};
class B : public A {
private:
void method() {}
};
int main(void) {
A* obj = new B();
obj->method(); // B::method is invoked, despite it being private
}
C ++中这种行为背后的逻辑是什么?
答案 0 :(得分:3)
请记住,method
的可见性仅在编译时解决,C ++没有运行时验证程序的概念。编译器看到的是虚拟A::method
,不私有。具体实现 被声明为私有,但只有在以编译器可见的方式直接调用此实现时才会相关,即如果您尝试通过B
调用它直接访问它
以下情况说明了它的逻辑:想象一下,如果B
没有公开地继承A
,而是私下 - 这在C ++中是允许的,并且在继承本身是一个实现时使用详细信息,例如继承自stack
的{{1}}类,但不希望公开矢量接口。在这种情况下,vector
无法访问,但B::method
工作正常,即使对象是A::method
实例。
正如Kerrek SB所说,Java在这里保护您免受一类错误的侵害,代价是删除合法选项。
答案 1 :(得分:2)
对于虚拟私有方法部分,这允许实现NVI pattern,以便您可以在使用继承的情况下进行不变检查或设置/拆除。
以下是锁定和后置条件验证的示例:
class base {
public:
virtual ~base() = default;
// Calls the derived class' implementation in a thread-safe manner.
// @return A value greater than 42.
int function() {
std::lock_guard<std::mutex> guard(mutex);
auto result = function_impl();
assert(result > 42);
return result;
}
private:
std::mutex mutex;
virtual int function_impl() = 0;
};
class derived : public base {
private:
virtual int function_impl() override {
return 0; // Whoops! A bug!
}
};
在Java中,这可以通过受保护的方法实现,但这会将实现细节泄露给派生类的派生类,这可能是不受欢迎的。
至于私有化,否则公众成员参与其中,如果某人突然在function_impl
中公开base
,则不会破坏派生类。我不是说这样做是个好主意,但C ++通常只是假设你知道自己在做什么,因此它是一种如此灵活的语言。