【问题标题】:Inheriting from nested structs: templates and pointers从嵌套结构继承:模板和指针
【发布时间】:2011-09-04 18:34:55
【问题描述】:

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

嵌套结构是 Base::Node,我想向 Base::Node 添加一个字段 b,然后使用 Derived,如主文件所示。当我将顶部的#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() 方法不满意?

谢谢!

#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;
}

【问题讨论】:

    标签: c++ templates inheritance nested-class


    【解决方案1】:

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

    • 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!
    

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

    【讨论】:

      【解决方案2】:

      回答你的第二个问题:

      如果你覆盖一个虚函数,签名必须匹配。这条规则的唯一例外是,如果在基类中函数返回一个指针或对某个类B 的引用,那么覆盖方法可以返回指针或引用类型D,其中D 派生自B (这称为返回类型协方差)。话虽如此,您的GetN 工作的原因一定很清楚——DNode 派生自Node,基类函数返回Node*,覆盖程序返回DNode*

      现在让我们看看GetNAddr。基类方法返回Node**pointer to Node*。您可以在派生类的重写函数中更改此返回类型如果它要返回从 Node 派生的东西*。但这自然是不可能的,因为指针不能有派生类。 DNode* 不是从 Node* 派生的 - 因此编译器会抱怨

      【讨论】:

      • 返回DNode** 也是没有意义的:函数Base&lt;T&gt;::GetNAddr() 始终不变地返回&amp;n,它始终是Node** 类型。这里甚至没有发生任何多态性。
      猜你喜欢
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 2017-05-15
      • 2020-05-03
      • 2021-08-11
      • 2015-03-26
      相关资源
      最近更新 更多