2012-07-04 62 views
0

我的理解是typedef作爲類型的同義詞,或者可以用作特定類型的別名。此外,下面的簡化代碼完美地構建。這裏的問題是,如果我在主函數改變第二行:typedef同義替換

Array<int>::ArrayIter<T> pa = a.begin(); // substituting back the typedef 「iterator」 to its original form of ArrayIter<T>. 

我得到編譯過程中出現以下錯誤信息:

「ArrayIter」不是「陣列」

成員

但是,使用「typedef」(迭代器)符號完美編譯的代碼。爲什麼是「迭代」和ArrayIter突然沒有任何的代名詞更多:

參考下面的代碼:

template<class T> class ArrayIter { 
public: 
ArrayIter(T* p) : m_p(p) { 
} 

private: 
T* m_p; 
}; 

template<class T> class Array { 

public: 
    Array(int size) throw (const char*) { 
    if (size > 0) { 
     m_p = new T[size]; 
     m_size = size; 
    } else { 
    throw "Array: invalid array dimension"; 
} 
    } 

    // typedef and methods to support the new iterator for this class 
    typedef ArrayIter<T> iterator; 

    ArrayIter<T> begin() { 
    return ArrayIter<T>(m_p); 
    } 

private: 
    T* m_p; 
    int m_size; 
}; 


int main(int argc, char* argv[]) { 

    Array<int> a(10); 
    Array<int>::iterator pa = a.begin(); 

return 0; 
} 

回答

1

由於錯誤說,ArrayIter不是Array的成員:它是一個單獨的類,在周圍的名稱空間中聲明。因此,Array<int>::ArrayIter<T>是無效的,應該只是ArrayIter<int>

iteratorArray成員,所以Array<int>::iterator有效的,並且是用於ArrayIter<int>的別名。

+0

謝謝麥克所有的答案。我是一個新成員,真的很看重這個網站。感謝你們! –

0

ArrayIter不是一個嵌套類中Array所以Array::ArrayIter將是無效申報。 ArrayIter僅在全局範圍內定義,因此您可以ArrayIter<int> iter = a.begin();。 typedef iteratorArray內定義,因此您可以將其作爲Array<int>::iterator訪問。

0

ArrayIter<T>絕對不是Array的成員,當它在外面宣佈時它怎麼可能?

您理解中的差距是範圍的工作原理。

class A 
{ 
}; 

A現在輸入全局命名空間。現在,讓我們假設第二類:

class B 
{ 
public: 
    typedef ::A C; 
}; 

CB中定義的,所以它的全名是B::C。但是,A仍然處於全局命名空間! typedef它不會改變原名稱的範圍,因此在這種情況下,A永遠不會是B的成員。

在結束 - 在全局命名空間,如下(從您的代碼所)是相同的:

Array<int>::iterator pa = a.begin(); 

相同

ArrayIter<int> pa = a.begin(); 
+0

謝謝你的澄清非常Griwes。 –

0

我沒有看到變體之間的任何等價。 ArrayIter不是一種類型,它是模板。您示例中的typedef名稱iterator指的是ArrayIter模板的特定專業化。在Array<int>裏面會參考ArrayIter<int>。在Array<double>裏面會參考ArrayIter<double>。這正是您要求編譯器通過您的typedef所做的。

它不以任何方式將ArrayIter模板帶入Array類。它仍然不是成員。它仍然存在於全局命名空間中,而Array<>::iterator只是指它。

最重要的是,你完全不清楚T你試圖參考main裏面。那裏沒有T

如果你想帶ArrayIterArray爲模板,你可以使用C++ 11的標準,稱爲「模板類型定義」或「模板別名宣言」

template <typename T> 
class Array { 
    ... 
    template <typename U> using ArrayIter = ::ArrayIter<U>; 
    ... 
}; 

現在,一個新的功能,您可以使用Array::ArrayIter作爲模板。

0

那麼,你說你想「撤消」typedef。您的typedef看起來像這樣:

typedef ArrayIter<T> iterator; 
一個Array [INT]內使用時

,給出的行

Array<int>::iterator pa = a.begin(); 

這種 「膨脹」 到

typedef ArrayIter<int> iterator; 

所以,它使用的typedef ,你可以手動撤消typedef得到

ArrayIter<int> pa = a.begin(); 

它工作得很好:-)

基本上,typedef被命名爲「Array [int] :: iterator」,而不僅僅是「迭代器」。

0

這是因爲您的迭代器在Array的範圍內定義,而您的ArrayIter在全局範圍內定義。要實現你說的話,你應該把ArrayIterArray

template<class T> class Array { 

public: 
    template<class T> class ArrayIter { 
    public: 
     ArrayIter(T* p) : m_p(p) { 
     } 

    private: 
     T* m_p; 
    }; 


    Array(int size) throw (const char*) { 
     if (size > 0) { 
      m_p = new T[size]; 
      m_size = size; 
     } else { 
      throw "Array: invalid array dimension"; 
     } 
    } 

    // typedef and methods to support the new iterator for this class 
    typedef ArrayIter<T> iterator; 

    ArrayIter<T> begin() { 
     return ArrayIter<T>(m_p); 
    } 

private: 
    T* m_p; 
    int m_size; 
}; 


int main(int argc, char* argv[]) { 

    Array<int> a(10); 
    Array<int>::ArrayIter<int> pa = a.begin(); 

    return 0; 
}