在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)
正如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)