2011-09-04 54 views
2

我想在C++中添加一些附加字段到嵌套結構中,並且設計規定我想通過繼承來實現。我得到一個錯誤,好奇地取決於我正在處理類型T *還是類型T **。我很困惑,希望有人幫助我理解這裏發生的事情。從嵌套的結構繼承:模板和指針

嵌套結構是Base :: Node,我想添加一個字段b到Base :: Node,然後使用Derived,如主要所示。當我將頂端的#define設置爲0時,所有內容都可以編譯並正常工作。當我改變#定義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; 
} 

回答

1

要回答你的第二個問題:

如果重寫虛函數,簽名必須匹配。此規則唯一的例外是,如果在基類中該函數返回某個類的指針或引用B,則覆蓋方法可以返回指針或引用類型D,其中D從B派生(這是calles返回類型協方差)。話雖如此,但必須清楚爲什麼你的GetN工作 - DNode派生自Node和基類函數返回Node*和覆蓋返回DNode*

現在讓我們看看GetNAddr。基類方法返回Node**pointer to Node*。如果要返回派生自節點 *的某些內容,則可以在派生類中的重寫函數中更改此返回類型。但這自然不可能,因爲指針不能派生類。 DNode*不是從Node*衍生 - 因此編譯器會抱怨

+0

返回'DNode **'也是沒有意義的:函數'Base :: GetNAddr()'總是不變地返回'&n',它總是'Node **'類型。這裏甚至沒有任何多態。 –

2

問題不在於使用嵌套結構或模板,但隨着指針的指針和繼承:

  • 基地*可容納​​派生*的一個實例,以及所以Base *可以被下載到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! 

最後一行將導致一些任意的錯誤。因此,這種分配是不允許的。