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

发布于 2024-12-03 01:42:01 字数 1987 浏览 1 评论 0原文

我正在尝试向 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() 方法不满意?

谢谢!

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

I am trying to add some additional fields to a nested struct in C++, and the design dictates that I want to do so via inheritance. I'm getting an error that curiously depends on whether I'm working with type T* or type T**. I'm fairly confused and would appreciate somebody helping me to understand what's happening here.

The nested struct is Base::Node, and I want to add a field, b, to Base::Node then use Derived as shown in the main. When I set the #define at the top to 0, everything compiles and works fine. When I change the #define to 1, I get the following compiler error:

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**’

Could somebody help me understand

  1. Whether this is the right way to be doing this, and if there is a better way, and

  2. Why the compiler is happy with the GetN() methods but not the GetNAddr() methods?

Thanks!

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我家小可爱 2024-12-10 01:42:01

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

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

最后一行将导致一些任意错误。因此,不允许进行此类分配。

The problem is not with nested structs or templates, but with pointers to pointers and inheritance:

  • Base* can hold an instance of Derived*, and so Base* can be down-casted to Derived*.
  • Base** can not hold an instance of Derived**, and so can't be down-casted to Derived**.

If Base** could hold an array of Derived's, you could have done the following:

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!

The last line would have resulted in some arbitrary error. Therefore, that kind of assignment is not allowed.

離人涙 2024-12-10 01:42:01

回答你的第二个问题:

如果你重写虚拟函数,签名必须匹配。此规则的唯一例外是,如果在基类中函数返回对某个类 B 的指针或引用,则重写方法可以返回对类型 D 的指针或引用code> 其中 D 源自 B(这称为返回类型协方差)。话虽如此,您必须清楚为什么 GetN 可以工作 - DNode 派生自 Node 并且基类函数返回一个 Node * 并且重写器返回 DNode*

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

To answer your second question:

If you override a virtual function, the signatures have to match. The only excetion of this rule is that if in the base class the function returns a pointer or a reference to some class B, then the overriding method can return pointer or reference to type D where D is derived from B (this is calles return type covariance). Having said this, it must be clear why your GetN works - DNode is derived from Node and the base class function returns a Node* and the overrider returns DNode*.

Now let's look at GetNAddr. The base class method returns a Node** or pointer to Node*. You could change this return type in an overriding function in the derived class if it were to return something that is derived from Node*. But that is naturally impossible, since a pointer cannot have derived classes. DNode* is not derived from Node* - hence the compiler complains

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文