【问题标题】:c++ base private method can be accessed after casting itself to derived class?将自身转换为派生类后可以访问c++基本私有方法吗?
【发布时间】:2018-09-20 22:12:37
【问题描述】:

我在使用 CRTP(奇怪的重复模板模式)时发现了这一点。

template <typename T>
class Base {
private:
    void f() {
        //when T has its own f(), it calls that
        //when T doesn't have, it calls itself, which is invoked recursively
        //but i expect the compiler to complain that f() is private when T doesn't have its own f()
        static_cast<T*>(this)->f();
    }

public:
    void g() {
        f();
    }
};

class Derived : public Base<Derived> {};

我以为我理解publicprotectedprivate,但对于这种情况,我好像错了。任何解释表示赞赏!

【问题讨论】:

    标签: c++ private crtp


    【解决方案1】:

    这仅在阴影声明为public 时有效。见this example

    class Derived : public Base<Derived> {
    private:
        void f() { }
    };
    
    void x(Derived* d) {
        d->g();
    }
    

    你得到:

    <source>: In instantiation of 'void Base<T>::f() [with T = Derived]':
    <source>:13:9:   required from 'void Base<T>::g() [with T = Derived]'
    <source>:23:10:   required from here
    <source>:8:9: error: 'void Derived::f()' is private within this context
             static_cast<T*>(this)->f();
             ^~~~~~~~~~~
    <source>:19:10: note: declared private here
         void f() { }
              ^
    

    如果函数没有在Derived 中被隐藏,则调用与this-&gt;Base&lt;Derived&gt;::f() 相同,这必须是合法的,因为Base 是唯一可以访问它的类。

    您的困惑也可能来自访问看似不同的对象。请记住,访问修饰符按范围而不是实例限制访问。在Base 中声明的任何方法都可以任何Base 实例的私有成员,而不仅仅是this 的。

    【讨论】:

    • 我想我明白如果你把 private 放在那里,它会引发抱怨。让我困惑的是,在我将this 转换为Derived 类型后,f()Derived 的私有,为什么它可以访问f()
    • 如果f()Derived 中定义为私有方法,则它不起作用,如示例所示。如果f() 没有被遮蔽,则没有问题,因为f()Base 的私有成员。 Derived 无法访问它:如果Base 无法访问,那么将无法使用它。编译器静态知道对象是 Derived 的事实不会改变访问规则:否则,您可以通过将 Derived 强制转换为 Base 来规避该检查,这不是非常有效的访问控制.
    • 感谢您的跟进。但我很抱歉,我还是不明白。 1.你能帮我举个例子来解释otherwise, you could circumvent that check by casting your Derived to a Base, which wouldn't be very effective access control吗? 2.当Derived没有f()时,static_cast&lt;T*&gt;(this)-&gt;f();this-&gt;Base&lt;Derived&gt;::f()是一样的吗?对我来说,我们将在static_cast&lt;T*&gt;(this) 之后得到Derived 指针,因为它是Derived 类型,编译器应该检查f() 对该类型不可见然后失败。
    • @goldenretriever,您可能通过包含 CRTP 使您的示例比您需要的更复杂;这些规则都适用于任何 BaseDerived : Base 类对。对于第 1 点:static_cast&lt;Base*&gt;(static_cast&lt;Derived*&gt;(this))-&gt;f()。对于第 2 点:Derived 没有声明 f(),它的唯一声明是 Base::fBase 的任何成员都可以访问它。 Base::f() 不会仅仅因为继承而被“重命名”为 Derived::f():毕竟,Derived 根本无法访问 f()
    • @goldenretriever, static_cast&lt;T*&gt; 不会改变被指向对象的性质。此外,访问控制不是由您尝试访问的对象应用的:它是由范围应用的。 Base 的任何方法都可以访问Base 类的任何成员,以及它的任何实例的任何成员。请参阅不使用 CRTP 的 this other example,如果它解决了任何问题,或者它是否可以帮助您以不涉及 CRTP 的方式提出问题,请告诉我。
    猜你喜欢
    • 2013-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多