Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在C+中调用私有成员函数+;_Java_C++_Inheritance_Virtual Functions - Fatal编程技术网

Java 在C+中调用私有成员函数+;

Java 在C+中调用私有成员函数+;,java,c++,inheritance,virtual-functions,Java,C++,Inheritance,Virtual Functions,我来自Java,那里不允许减少派生类中的访问修饰符。对于Instance,以下内容不是用Java编译的: public class A{ public void foo(){ } } public class B extends A{ @Override private void foo(){ } //compile-error } 但是,C++中很好: struct A { A(){ } virtual ~A(){ } A(A&&a

我来自Java,那里不允许减少派生类中的访问修饰符。对于Instance,以下内容不是用Java编译的:

public class A{
    public void foo(){ }
}

public class B extends A{
    @Override
    private void foo(){ }  //compile-error
}
<>但是,C++中很好:

struct A {
    A(){ }
    virtual ~A(){ }
    A(A&&){ }
public:
    virtual void bar(){ std::cout << "A" << std::endl; }
};

struct B : public A{
private:
    virtual void bar(){ std::cout << "B" << std::endl; }
};

int main()
{
    A *a = new B;
    a -> bar(); //prints B
}
结构A{ A(){} 虚拟~A(){} A(A&&{} 公众:
虚拟空心条(){std::cout正如您所观察到的,访问说明符是基于指针的类型工作的,而不是基于动态类型。因此,在本例中,在B中指定private意味着无法通过指向B的指针访问函数。因此,在客户端不应使用point的情况下,这可能有助于保持锁定ers到B(或在堆栈上创建B)。基本上,在B的构造函数是私有的情况下,您通过返回
唯一\u ptr
的工厂创建B(可能还有A的其他子级)。在这种情况下,您可以将B的所有方法都指定为私有。原则上,这可以防止客户端“滥用”通过向下动态转换唯一的_ptr,然后直接访问B的接口,可以创建该接口

<>我并不认为这是应该做的;它是一种比C++更为流行的JavaY方法。一般来说,如果客户希望通过基类指针在堆栈上使用派生对象而不是堆上,则应该是能够的。它提供更好的性能,而且更易于推理。它在通用代码中也更好。

编辑:我想我应该澄清一下。考虑下面的代码:

enum class Impl {FIRST, SECOND, THIRD};

unique_ptr<A> create(Impl i) {
  ...
}
如果用户有这样的代码,并且您删除或重命名了类B,则他们的代码将中断。通过将B的所有方法设置为私有,您可以使B指针对用户无效,从而确保他们按照预期使用接口


正如我前面所说的,在C++中,我并不特别提倡用这种方式编程。但是,可能确实需要派生类是纯实现细节;在这种情况下,更改访问说明符可以帮助实现它。默认情况下,结构是公共的。就个人而言,我不建议更改访问级别,因为我认为这可能会令人困惑。但是,我不知道为什么它会被视为不安全,也不知道为什么它会有用。与此相关,由非虚拟公共函数调用私有虚拟函数可能会很有用。请参阅NVI(非虚拟接口)习惯用法。@JamesAdkison它是“不安全的”因为它允许外部代码直接调用私有函数,这与私有函数的整个观点相矛盾。@immibis我的意思是从UB的角度来看是不安全的。基类希望它是公共的,所以在我看来,派生类期望公共访问之外的任何东西都是错误的。另一个答案:

auto a = create(Impl::FIRST);
auto b = dynamic_cast<B *>(a.get());
// Use b below, potentially avoiding vtable