C ++:模板继承了递归类:不可能的三重威胁?

时间:2011-02-12 01:23:38

标签: c++ templates inheritance recursion compilation

因此,假设您有一个递归的基类(例如链表)和派生类。派生类应该重用基类中的构造函数,因为您不想编写冗余代码。你可以尝试一下这个显而易见的事情,它不会起作用:

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实例之后抽出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的构造函数时,templating导致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。

的这个问题

1 个答案:

答案 0 :(得分:12)

问题是基类Base<T, Derived<T> >是依赖基类,因为它依赖于模板参数,但next不是依赖名,因为它不依赖于模板参数。编译器不会在依赖基类中查找非依赖名称。

您可以通过next访问this->依赖this->next 来解决此问题:

{{1}}

您可以从C ++ FAQ Lite文章"Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?"

中找到更多信息