CRTP with Protected Derived Member
在crtp模式中,如果我们希望将派生类中的实现函数保持为受保护的,就会遇到问题。我们必须将基类声明为派生类的朋友,或者使用类似的方法(我没有在链接的项目上尝试过该方法)。是否有其他(简单)方法允许将派生类中的实现函数保持为受保护的?
编辑:下面是一个简单的代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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; } |
上面的代码给出了使用g++4.5.1的
这根本不是问题,在派生类中用一行来解决:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #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 ); } |
正如Lapk推荐的那样,问题可以通过简单的friend类声明来解决:
1 2 3 4 5 6 | class D: public C<D> { friend class C<D>; // friend class declaration protected: void foo() { } }; |
但是,它公开派生类的所有受保护/私有成员,并要求为每个派生类声明使用自定义代码。
以下解决方案基于链接的文章:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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; } |
PS:如果您不相信编译器会优化掉这些引用,您可以用下面的
1 2 3 4 | int base_bar() { return Accessor::base_bar(_instance_ref); } private: #define _instance_ref *static_cast<D*>(this) //D& derived() { return *(D*)this; } |