В одном из моих проектов я использую тот же подход CRTP (производный от enable_crtp
) как в ответе 1 здесь: Как передать параметры шаблона в CRTP?
Однако у меня есть необходимость извлечь из производных классов тоже. Есть ли способ заставить это работать без возврата только к static_cast указателю this, но с помощью метода self () из базового класса Enable CRTP?
#include "EnableCRTP.h"
template<typename DERIVED>
class BASE : public EnableCRTP<DERIVED>
{
friend DERIVED;
public:
void startChain()
{
self()->chain();
}
};
template<typename DERIVED>
class Derived1 : public BASE<Derived1<DERIVED> >
{
public:
void chain()
{
std::cout << "Derived1" << std::endl;
//self()->chain2(); <- compile Error
static_cast<DERIVED*>(this)->chain2(); // <-Works
}
};
class Derived2 : public Derived1<Derived2>
{
public:
void chain2()
{
std::cout << "Derived2" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Derived2 der;
der.startChain();
return 0;
}
Вы можете передать самый производный класс в качестве параметра шаблона базовому классу CRTP, чтобы он имел доступ ко всем своим членам. Вместо
template<typename DERIVED>
class Derived1 : public BASE<Derived1<DERIVED> >
Использование:
template<typename DERIVED>
class Derived1 : public BASE<DERIVED>
Есть и другие проблемы с вашим кодом. Например, вы не можете напрямую позвонить self()
как вы делаете, потому что компилятор не знает, что self
является членом базового класса (который зависит от параметра шаблона). Вместо этого позвоните this->self()
, Увидеть эта запись FAQ.
Чтобы сделать то, что вы хотите, вы только передаете самый производный класс через CRTP. В этом случае вам нужно изменить определение Derived1 на следующее:
template<typename DERIVED>
class Derived1 : public BASE< DERIVED >
{
public:
void chain()
{
std::cout << "Derived1" << std::endl;
this->self()->chain2(); // should work now
//static_cast<DERIVED*>(this)->chain2(); // <-Works
}
};
Кроме того, при использовании CRTP с иерархиями классов, как правило, лучше настроить иерархию так, чтобы класс либо был разработан для наследования (и, следовательно, является шаблоном, которому передан класс DERIVED), либо является листом иерархии и не является производным от Эти листовые классы не должны быть шаблонами вообще.