有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

私有方法的动态绑定:java vs C++

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


共 (2) 个答案

  1. # 1 楼答案

    至于虚拟私有方法部分,这允许实现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中,这可以通过受保护的方法实现,但这会将实现细节泄露给派生类的派生类,而这些派生类可能是不需要的

    至于私有化公共成员部分,如果有人突然在base中公开function_impl,它不会破坏派生类。我并不是说这是一个很好的想法,但是C++通常假设你知道你在做什么,因此它是一种如此灵活的语言。p>

  2. # 2 楼答案

    <>请记住,^ { CD1>}的可见性完全在编译时得到解决,C++没有运行时验证器的概念。编译器看到的是一个虚拟的A::method,它是而不是私有的。具体实现声明为私有,但这仅在以编译器可见的方式直接调用此实现时才相关,即,如果您试图通过^{调用它来直接访问它

    逻辑由下面的例子说明:想象如果{{CD3}}没有从^ {{CD5>}继承,而是私下的——这是C++中允许的,并且当继承本身是实现细节时使用,例如对于从{{CD7>}继承的^ {< CD6>}类,但不希望暴露向量接口。在这种情况下,B::method是不可访问的,但是A::method工作正常,即使对象是B实例

    正如Kerrek SB所说,Java正在保护您免受一类错误的影响,代价是删除合法选项