我一直在使用c ++中的CRTP进行实验,而且我遇到了为基类编写通用复制构造函数来复制任何其他派生类的问题。假设我有这个CRTP基类。
template <class Derived>
class Base {
public:
//Static dispatch function
void print() const {
static_cast<Derived *>(this)->print();
}
protected:
//Protected so it can only be derived
Base(int i) : i(i) { }
//Attempt at a generic copy constructor
template <class Sibling>
Base(const Base<Sibling>& rhs) : i(rhs.i) { }
const int i;
};
现在,如果我写两个派生类:class Derived1 : public Base<Derived1>
和class Derived2 : public Base<Derived2>
,我给Derived2一个复制构造函数,它接受像这样的Derived1:
class Derived2 : public Base<Derived2> {
public:
//Copy constructor
Derived2(const Derived1& rhs) : Base(rhs) { }
...
};
我收到编译错误。 error: 'i' is a protected member of 'Base<Derived1>'
这是因为Derived1和Derived2是两个不属于同一类家庭的独特类型,因此他们无法访问非公开成员,对吗?
在Base类中如果我声明template <class Sibling>
是Base的类朋友,它编译并复制正常,但我只希望Base能够访问复制构造函数中的派生成员。如果我将i
可见性更改为public,它也可以工作,但这会破坏任何类型的封装。
理想的做法是使复制构造函数成为所有派生类的友元函数。
template <class Derived>
class Base {
...
//Friend Declaration
template <class Sibling>
friend Base::Base(const Base<Sibling>& rhs);
//Generic copy constructor
template <class Sibling>
Base(const Base<Sibling>& rhs) : i(rhs.i) { }
...
};
但这会导致相同的编译器错误。我宣布朋友功能错了吗?或者这是不可能做到的?如果有,还有其他方法可以从一个派生类转换到另一个派生类吗?