Итак, скажем, у вас есть базовый класс, который является рекурсивным (например, связанный список), а также производный класс.Производный класс должен повторно использовать конструктор из базового класса, потому что вы не хотите писать избыточный код.Вы можете попробовать очевидную вещь, и она не будет работать:
class Base {
public:
Base(int size) {
if (size <= 0) { next = NULL; }
else { next = new Base(size - 1); }
}
void print() {
cout << " Base ";
if (next != NULL) { next->print(); }
}
protected:
Base *next;
};
class Derived: public Base {
public:
Derived(int size) : Base(size) {}
void print()
{
cout << " Derived ";
if (next != NULL)
{ next->print(); }
}
};
int main()
{
Derived d2(5);
d2.print();
cout << "\n";
return 0;
}
Это не будет работать - когда вы создаете экземпляр Derived, он создает один экземпляр Derived, а затем вызывает конструктор класса Base, который выкачивает Baseэкземпляр после базового экземпляра.Если вы запустите «main», вы получите:
Derived Base Base Base Base Base
Теперь вы можете стать умнее и использовать что-то вроде следующего шаблона проектирования: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern, который решит все ваши проблемы.Посмотрите на следующий действительно аккуратный код:
template <class targetT, class recursiveT>
class Base {
public:
Base(targetT size) {
if (size <= 0) { next = NULL; }
else { next = new recursiveT(size - 1); }
}
void print() {
cout << " Base ";
if (next != NULL)
{ next->print(); }
}
protected:
recursiveT *next;
};
class Derived: public Base<int, Derived> {
public:
Derived(int size) : Base<int, Derived>(size) {}
void print()
{
cout << " Derived ";
if (next != NULL)
{ next->print(); }
}
};
int main()
{
Derived d1(5);
d1.print();
cout << "\n";
return 0;
}
Это проходит тест - когда мы возвращаемся из конструктора Derived обратно в конструктор Base, шаблоны заставляют Base откачивать экземпляры Derived.Ухоженная!Если вы запустите main, вы увидите следующее:
Derived Derived Derived Derived Derived Derived
Как вы и хотели!
Теперь все становится странным.Скажем, мы хотели, чтобы Base и Derived сами были шаблонами;скажем, что это связанные списки, и мы хотим, чтобы они содержали произвольные данные.
Итак, мы можем продвинуться немного дальше:
template <class targetT, class recursiveT>
class Base {
public:
Base(targetT size) {
if (size <= 0) { next = NULL; }
else { next = new recursiveT(size - 1); }
}
void print() {
cout << " Base ";
if (next != NULL)
{ next->print(); }
}
protected:
recursiveT *next;
};
template <class T>
class Derived: public Base<T, Derived<T> > {
public:
Derived(int size) : Base<T, Derived<T> >(size) {}
void print()
{
cout << " Derived ";
if (next != NULL)
{ next->print(); }
}
};
int main()
{
Derived<int> d1(5);
d1.print();
cout << "\n";
return 0;
}
Но, что удивительно, компиляция теперь не удалась с g ++:
X.cpp: In member function ‘void Derived<T>::print()’:
X.cpp:33: error: ‘next’ was not declared in this scope
Кто-нибудь видит, почему так должно быть?Я почти подозреваю, что G ++ не так, здесь.У меня есть эта проблема с gcc версии 4.3.2 и gcc версии 4.4.1.