4

这在 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++ 中这种行为背后的逻辑是什么?

4

2 回答 2

3

请记住, 的可见性method纯粹在编译时解决,C++ 没有运行时验证器的概念。编译器看到的是一个 virtual A::method,它不是私有的。具体实现声明为私有的,但这仅在以编译器可见的方式直接调用此实现时才相关,即如果您尝试通过调用它直接访问它B

它的逻辑由以下案例说明:想象一下,如果B没有从A公共继承,而是私有继承——这在 C++ 中是允许的,并且在继承本身是实现细节时使用,例如对于stack继承自的类vector,但不想要暴露向量接口。在这种情况下,这将是一个B::method不可访问的功能,但A::method工作得很好,即使对象是一个B实例。

正如 Kerrek SB 所说,Java 在这里保护您免受一类错误,但代价是删除合法选项。

于 2013-11-24T22:28:44.767 回答
2

至于虚拟私有方法部分,这允许人们实现NVI 模式,以便您可以在使用继承的情况下进行不变量检查或设置/拆卸。

这是一个带有锁和后置条件验证的示例:

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公开 in base,它不会破坏派生类。我并不是说这样做是个好主意,但 C++ 通常只是假设您知道自己在做什么,因此它是一种非常灵活的语言。

于 2013-11-24T22:59:19.373 回答