带有受保护派生成员的CRTP

ami*_*mit 24 c++ crtp

CRTP模式中,如果我们想要将派生类中的实现函数保持为受保护,则会遇到问题.我们必须将基类声明为派生类的朋友或使用类似的东西(我没有尝试过链接文章的方法).是否有其他(简单)方法允许将派生类中的实现函数保持为受保护?

编辑:这是一个简单的代码示例:

template<class D> 
class C {
public:
    void base_foo()
    {
        static_cast<D*>(this)->foo();
    }
};


class D:  public C<D> {
protected: //ERROR!
    void foo() {
    }   
};

int main() {
    D d;
    d.base_foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码给出error: ‘void D::foo()’ is protected了g ++ 4.5.1,但是如果protected被替换为compiles public.

lap*_*apk 30

它根本不是问题,在派生类中用一行解决:

friend class Base< Derived >;

#include <iostream>

template< typename PDerived >
class TBase
{
 public:
  void Foo( void )
  {
   static_cast< PDerived* > ( this )->Bar();
  }
};

class TDerived : public TBase< TDerived >
{
  friend class TBase< TDerived > ;
 protected:
  void Bar( void )
  {
   std::cout << "in Bar" << std::endl;
  }
};

int main( void )
{
 TDerived lD;

 lD.Foo();

 return ( 0 );
}
Run Code Online (Sandbox Code Playgroud)


pix*_*ase 5

正如lapk推荐的那样,问题可以通过简单的友元类声明来解决:

class D:  public C<D> {
    friend class C<D>;      // friend class declaration
protected:
    void foo() {
    }
};
Run Code Online (Sandbox Code Playgroud)

但是,这会公开派生类的所有受保护/私有成员,并且需要为每个派生类声明自定义代码。

以下解决方案基于链接的文章

template<class D>
class C {
public:
    void base_foo() { Accessor::base_foo(derived()); }
    int base_bar()  { return Accessor::base_bar(derived()); }

private:
    D& derived() { return *(D*)this; }

    // accessor functions for protected functions in derived class
    struct Accessor : D
    {
        static void base_foo(D& derived) {
            void (D::*fn)() = &Accessor::foo;
            (derived.*fn)();
        }
        static int base_bar(D& derived) {
            int (D::*fn)() = &Accessor::bar;
            return (derived.*fn)();
        }
    };
};

class D : public C<D> {
protected: // Success!
    void foo() {}
    int bar() { return 42; }
};

int main(int argc, char *argv[])
{
    D d;
    d.base_foo();
    int n = d.base_bar();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

PS:如果您不相信编译器会优化引用,您可以使用derived()以下函数替换该函数#define(使用 MSVC 2013 可以减少 20% 的反汇编代码行):

    int base_bar() { return Accessor::base_bar(_instance_ref); }

    private:
    #define _instance_ref *static_cast<D*>(this)   //D& derived() { return *(D*)this; }
Run Code Online (Sandbox Code Playgroud)