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

时间:2015-12-22 03:47:08

标签: java c++ inheritance virtual-functions

我来自Java,不允许减少派生类中的访问修饰符。对于instnace,以下内容不能用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
}

DEMO

它可能在哪里有用?这样做是否安全?

1 个答案:

答案 0 :(得分:3)

正如您所观察到的,访问说明符基于指针的类型而不是基于动态类型。因此,在这种情况下在B中指定private只是意味着无法通过指向B的指针访问函数。因此,在客户端不应使用指向B的指针(或创建B&#39; s在堆栈上)。基本上,在B&#39的构造函数是私有的情况下,您通过返回unique_ptr<A>的工厂创建B(以及可能的A的其他子项)。在这种情况下,您可以将B&B的所有方法指定为私有。原则上,这可以防止客户滥用&#34;接口通过向下动态转换unique_ptr然后直接访问B接口。

我真的不认为应该这样做;它是一种比C ++更Java-y的方法。通常,如果客户端想要通过基类指针在堆栈上而不是在堆上使用派生对象,那么它们应该能够。它提供了更好的性能,并且更容易推理。它在通用代码中也更有效。

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

enum class Impl {FIRST, SECOND, THIRD};

unique_ptr<A> create(Impl i) {
  ...
}

假设这是创建使用A接口的具体实例的唯一方法。我可能希望派生类是纯粹的实现细节。例如,我可以在不同的类中实现三个实现中的每一个,然后决定将三个中的两个组合成一个具有不同选项的类,依此类推。它不属于用户的业务;他们的世界只是A的界面和create功能。但现在假设用户恰好查看源并知道FIRST实现是使用B实现的。他们想要更好的性能,所以他们这样做:

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

如果用户有这样的代码,并且你删除或重命名了B类,他们的代码就会中断。通过将所有B方法设为私有,您可以使b指针对用户无用,确保它们按预期使用接口。

正如我之前所说,我并不特别提倡用C ++编程。但是在某些情况下,您确实需要派生类是纯粹的实现细节;在这些情况下,更改访问说明符可以帮助实施它。