我正在尝试在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**’
有人可以帮我理解
这是否是正确的方法,如果有更好的方法,
为什么编译器对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;
}
答案 0 :(得分:2)
问题不在于嵌套结构或模板,而是指向指针和继承的指针:
如果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*
。基类方法返回GetNAddr
或Node**
。如果要返回从Node * 派生的内容,则可以在派生类 中的覆盖函数中更改此返回类型。但这自然是不可能的,因为指针不能有派生类。 pointer to Node*
不是来自DNode*
- 因此编译器会抱怨