继承嵌套结构:模板和指针

时间:2011-09-04 18:34:56

标签: c++ templates inheritance nested-class

我正在尝试在C ++中为嵌套结构添加一些额外的字段,并且设计要求我通过继承来实现。我收到一个错误,奇怪地取决于我是使用T *类型还是键入T **。我很困惑,并希望有人帮我理解这里发生的事情。

嵌套结构是Base :: Node,我想在Base :: Node中添加一个字段b,然后使用Derived,如main所示。当我将顶部的#define设置为0时,一切都编译并正常工作。当我将#define更改为1时,我收到以下编译器错误:

main_inhtest.cpp: In instantiation of ‘Derived<int>’:
main_inhtest.cpp:52:   instantiated from here
main_inhtest.cpp:44: error: conflicting return type specified for ‘Derived<T>::DNode** Derived<T>::GetNAddr() [with T = int]’
main_inhtest.cpp:24: error:   overriding ‘Base<T>::Node** Base<T>::GetNAddr() [with T = int]’
main_inhtest.cpp: In member function ‘Derived<T>::DNode** Derived<T>::GetNAddr() [with T = int]’:
main_inhtest.cpp:57:   instantiated from here
main_inhtest.cpp:44: error: invalid static_cast from type ‘Base<int>::Node**’ to type ‘Derived<int>::DNode**’

有人可以帮我理解

  1. 这是否是正确的方法,如果有更好的方法,

  2. 为什么编译器对GetN()方法感到满意而不满足GetNAddr()方法?

  3. 谢谢!

    #include <iostream>
    
    #define TRY_GET_N_ADDR 1
    
    template <typename T> class Base {
    public:
      Base() { n = new Node(); }
    
      struct Node
      {
        T a;
      };      
      virtual Node *GetN() { return n; }
      virtual Node **GetNAddr() { return &n; }  
    
      Node *n;
    };
    
    template <typename T> class Derived : public Base<T> {
    public:
      Derived() { Base<T>::n = new DNode(); }
    
      struct DNode : Base<T>::Node
      {
        T b;
      };
    
      // This method is fine
      DNode *GetN() { return static_cast<DNode *>(Base<T>::GetN()); }
    
    #if TRY_GET_N_ADDR
      // Compiler error here
      DNode **GetNAddr() { return static_cast<DNode **>(Base<T>::GetNAddr()); }
    #endif
    };
    
    int main (int argc, const char * argv[]) {
      Derived<int> d;
    
      d.GetN()->a = 1;
      d.GetN()->b = 2;
    
      std::cout << d.GetN()->a << " " << d.GetN()->b << std::endl;
    }
    

2 个答案:

答案 0 :(得分:2)

问题不在于嵌套结构或模板,而是指向指针和继承的指针:

  • Base *可以包含Derived *的实例,因此Base *可以下载到Derived *。
  • Base **无法保存Derived **的实例,因此无法将其下载到Derived **。

如果Base **可以包含Derived的数组,那么您可以完成以下操作:

Derived* pDerived;
Derived** ppDerived = &pDerived;
Base** ppBase = ppDerived; // not allowed in real world
*ppBase = new Base;        // should be safe, right?
pDerived->derivedFunc();   // invoked on instance of Base!

最后一行会导致一些任意错误。因此,不允许这种分配。

答案 1 :(得分:1)

回答你的第二个问题:

如果覆盖虚拟功能,则必须匹配签名。此规则唯一的例外是,如果在基类中函数返回指针或对某个类B的引用,则覆盖方法可以返回指向D的指针或引用,其中{{1}从B派生(这是calles返回类型协方差)。说完之后,必须清楚为什么D工作 - GetN派生自DNode,基类函数返回Node并且覆盖返回Node* }。

现在让我们看一下DNode*。基类方法返回GetNAddrNode**。如果要返回从Node * 派生的内容,则可以在派生类 中的覆盖函数中更改此返回类型。但这自然是不可能的,因为指针不能有派生类。 pointer to Node*不是来自DNode* - 因此编译器会抱怨