【问题标题】:Implementing: private structs in Class实现:类中的私有结构
【发布时间】:2015-07-17 02:34:33
【问题描述】:

我有一个 List 类,它使用两个对象:元素和迭代器

我考虑过制作元素和迭代器类,但最终决定使用结构。

V1。这行得通...

template <class T>
struct Element

template <class T>
struct Iterator



template <typename T>
class List {

public: 

typedef Iterator<T> iterator;


private:

};

如您所料,它允许使用 List 迭代器:

List<int> list;
List<int>::iterator iter = list.begin();

V2。另一种方法是在类中声明结构

template <typename T>
class List {

public:

    template <class T>
    struct Element

    template <class T>
    struct Iterator


private:


};

然而,在创建迭代器时必须包含第二个 就不那么优雅了,结构是公共的:

List<int> list;
List<int>::Iterator<int> iter = list.begin();

V3。涉及将结构设为私有,这是可取的:

template <class T>
class Iterator;


template <typename T>
class List {

public:


typedef Iterator<T> iterator;

private:

template <class T>
struct Element

template <class T>
struct Iterator

};

.

List<int> list;
List<int>::iterator iter list.begin();

Error 1 error C2079: 'begin' uses undefined class 'Iterator<T>'  main.cpp   216

问题:

如何将结构设为私有,允许公共访问 Iterator 并保持 List::iterator 语法?

例如 List::iterator iter list.begin();

注意: 迭代器依赖于元素

代码:

#ifndef GUARD_List_h
#define GUARD_List_h

template <class T>
struct Element {

    Element() : prev(nullptr), next(nullptr), data(), t_flag(" ") {}

    Element<T>* prev;
    Element<T>* next;

    T data;
    int elem_ID;
    std::string t_flag;
};

template <class T>
struct Iterator {

    Iterator(Element<T>* e = nullptr) : elem(e) {}

    T& operator*(void) const {

        if (elem->t_flag == "sentinel"){ std::cerr << "No Element to De-Reference - End of List Reached"; }

        return elem->data;
    }

    T& operator++(void) {           // ++prefix

        elem = elem->next;
        return elem->data;
    }
    T operator++(const int) {               // postfix++

        elem = elem->next;
        return elem->prev->data;
    }
    T& operator--(const int) {          // --prefix

        elem = elem->prev;
        return elem->data;
    }
    T operator--(void) {            // postfix--

        elem = elem->prev;
        return elem->next->data;
    }

    Iterator<T>& operator+(const int val) {

        for (int i = 0; i < val; i++){

            elem = elem->next;
        }
        return *this;
    }
    Iterator<T>& operator-(const int val) {

        for (int i = 0; i < val; i++){

            elem = elem->prev;
        }
        return *this;
    }

    bool operator!=(const Iterator<T>& rhs) const {

        return elem->elem_ID != rhs.elem->elem_ID;
    }
    bool operator==(const Iterator<T>& rhs) const {

        return elem->elem_ID == rhs.elem->elem_ID;
    }
    bool operator>(const Iterator<T>& rhs) const {

        return elem->elem_ID > rhs.elem->elem_ID;
    }
    bool operator<(const Iterator<T>& rhs) const {

        return elem->elem_ID < rhs.elem->elem_ID;
    }
    bool operator>=(const Iterator<T>& rhs) const {

        return elem->elem_ID >= rhs.elem->elem_ID;
    }
    bool operator<=(const Iterator<T>& rhs) const {

        return elem->elem_ID <= rhs.elem->elem_ID;
    }


    Element<T>* elem;

};




template <typename T>
class List {

public:
    List() : sentinel(new Element<T>), Element_count(0)  {

        sentinel->t_flag = "sentinel";

        // double link: sentinel to itself
        sentinel->next = sentinel;
        sentinel->prev = sentinel;

    }
    virtual ~List()  {

        Element<T>* index = sentinel->next;
        Element<T>* index_next = sentinel->next->next;

        while (index->t_flag != "sentinel"){

            delete index;
            index = index_next;
            index_next = index_next->next;
        }
        delete sentinel;        
    }


    typedef Iterator<T> iterator;   


    Iterator<T> begin(void) const {

        Iterator<T> it(sentinel->next);
        return it;
    }
    Iterator<T> end(void) const {

        Iterator<T> it(sentinel);
        return it;
    }

    void push_back(const T val)  {

        Element<T>* elem = new Element<T>;      // create Element<T> object         
        elem->data = val;                       // set Element<T> data

        sentinel->prev->next = elem;            // link: end of List to Element object
        elem->prev = sentinel->prev;            // link: Element object to end of List   

        elem->next = sentinel;                  // link: new end of List to sentinel    
        sentinel->prev = elem;                  // link: sentinel to new end of List                

        elem->elem_ID = Element_count++;        // update: Element_count on grow        
    }
    T at(const size_t pos)  const {

        return get_Element(pos)->data;
    }
    void del(const size_t pos) const  {

        Element<T>* elem = get_Element(pos);    // get: Element for deletion        

        elem->prev->next = elem->next;          // rejoin: double link
        elem->next->prev = elem->prev;          // rejoin: double link

        delete elem;

        Element_count--;                        // update: Element_count on shrink

    }
    void clear(void) {

        Element<T>* index = sentinel->next;
        Element<T>* index_next = sentinel->next->next;

        while (index->t_flag != "sentinel"){

            delete index;
            index = index_next;
            index_next = index_next->next;
        }

        // double link: sentinel to itself
        sentinel->next = sentinel;
        sentinel->prev = sentinel;

        Element_count = 0;

    }

    size_t size(void) const {
        return Element_count;
    }
    bool empty(void) const {

        if (Element_count == 0){ return true; }
        else { return false; }
    }


private:



    Element<T>* sentinel;                         // List sentinel
    size_t Element_count;                         // List size

    Element<T>* get_Element(const size_t pos) const     {

        if (empty())                        {
            std::cerr << "No Element - Empty List";
            throw;          
        }
        if (pos < 0 || pos >= Element_count){
            std::cerr << "No Element - Out of Range";
            throw;          
        }


        Iterator<T> it;

        if ((Element_count / 2) > pos) {                        // Determine efficent direction ? 

            it = begin()+1;
            while ( it.elem->elem_ID != pos ){  it++;   }
        }
        else {

            it = end()-1;                           
            while ( it.elem->elem_ID != pos ){  it--;   }
        }

        return it.elem;
    }




};
#endif

【问题讨论】:

  • 您知道 C++ 中的类和结构之间的区别,对吧?几乎没有。也就是说,我会将模板部分推迟到以后,它们不是回答您的问题所必需的,但它们会使问题复杂化。
  • 我的意思是让它们成为具有自己的头文件的实际类......然后包括它们。但我们不要被跟踪

标签: c++ struct iterator private


【解决方案1】:

就“优雅”而言,多余的typename 声明似乎是最大的问题:

如果你有一个嵌套类或结构,你不需要模板化它;它已经绑定到模板化的typename T 声明。

所以:

template <typename T>
class List {
public:
    struct Element;
    struct Iterator;
private:
};

允许您这样做:

List<int> x;
List<int>::iterator iter ( x.begin() );

由于Iterator 在公共方法中被返回,它不能被标记为private。另一方面,Element 纯粹是一个实现细节,可以标记为私有。您需要确保在使用它的任何方法之前声明它只是简单地向前声明。

template<typename T>
class List {
private:
    struct Element; // or struct Element { <impl> };
public:
    struct Iterator { < impl > };
private:
};

【讨论】:

  • 按描述添加结构会在元素中出现语法错误:错误 1 ​​错误 C2059:语法错误:'
  • 你还有像Iterator(Element&lt;T&gt;* e = nullptr) : elem(e) {} 这样的行吗?这些应替换为Iterator(Element *e = nullptr) : elem(e){} 等。
  • 类似地Iterator&lt;T&gt;&amp; operator+(const int val)变成Iterator&amp; operator+(...)
  • 非常感谢伙计们,我让迭代器公开,将元素设为私有并转发声明的元素,如下所示:“class Element;” @EyasSh 如果您将此添加到您的答案代码中,我会接受!
  • 我相应地修改了答案。
猜你喜欢
  • 2019-02-13
  • 2010-10-07
  • 2021-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多