【问题标题】:returning reference to class返回对类的引用
【发布时间】:2015-07-02 09:28:56
【问题描述】:

我有这样的代码:

#include <stdio.h>

class AbstractIterator{
    virtual void do_something() = 0;
};

class AbstractList{};

class Iterator : public AbstractIterator{
public:
   Iterator(const AbstractList & list) : list(list){};

   virtual void do_something() override{
       printf("hello\n");
   };

   const AbstractList & list;
};

class List : public AbstractList{
public:
  Iterator getIterator(){
     return Iterator(*this);
  }
};

int main(int argc, char** argv){
    List list;
    Iterator it = list.getIterator();

    it.do_something();

    return 0;
}

这可行,但我想将 getIterator() 方法“推送”到 AbstractList 类。为此,需要能够做到以下几点:

/* non const */
AbstractIterator &it = list.getIterator();
it.do_something();

如果没有动态分配,这是否可能以某种方式完成?

【问题讨论】:

  • 您要解决什么问题?为什么首先需要AbstractList
  • 是的,我需要它。这是非常大的代码的一部分,为了更容易理解,我只是将问题隔离开来。
  • 您将如何使用动态分配来做到这一点?我看不出这与动态分配有何关系。
  • @tobi303 - 我可以通过 Java 方式实现 - list.getIterator() 使用 return (AbstractIterator *) new Iterator(*this) 或者它可能返回智能指针以避免显式删除
  • “是的,我需要它。”没有回答他的问题。真的很难知道你想要实现什么。您的迭代器看起来不像迭代器,并且列表看起来也不像列表,因此您必须解释它是关于什么的,或者您使您的最小可编译示例真正minimal

标签: c++ c++11 reference return


【解决方案1】:

也许是这样

class AbstractIterator{
public:
    virtual void do_something() = 0;
};

class AbstractList
{
public:
    virtual AbstractIterator* getIterator() = 0;
};

class Iterator : public AbstractIterator{
public:
    Iterator(AbstractList& list) : list(list){}

    const Iterator operator=( const Iterator& other )
    {
        list = other.list;
        return *this;
    }

    virtual void do_something() override{
        printf("hello\n");
    }

    AbstractList& list;
};

class List : public AbstractList{
    Iterator iterator;
public:
    List() : iterator( *this ) {}
    AbstractIterator* getIterator() override
    {
        iterator = Iterator( *this );
        return &iterator;
    }
};

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

    List list;

    AbstractIterator* it = list.getIterator();
    it->do_something();

    return 0;
}

顺便说一句。重要的是要记住迭代器的有效性(列表的修改,虚拟析构函数等),这个例子非常基础:)

这个写的很快

  • 迭代器的失效函数应该是私有的,可以这样做,但它会使一些源复杂化
  • 注意iterface方法是由模板方法调用的——好习惯

来源:

class AbstractList;

class AbstractIterator{
public:
    AbstractIterator( AbstractList* list ) : list( list ), valid( true ) {}
    virtual bool moveNext() = 0;
    void doSomething()
    {
        if( isValid() )
        {
            do_something();
        }
    }

    bool isValid() { return valid && 0 != list; }
    void invalidate()
    {
        valid = false;
    }
protected:
    AbstractList* list;
private:
    virtual void do_something() = 0;
    bool valid;
};

class AbstractList
{
public:
    virtual ~AbstractList()
    {
        for( std::shared_ptr< AbstractIterator > it : iterators )
        {
            it->invalidate();
        }
        iterators.clear();
    }
    std::shared_ptr< AbstractIterator > iterator()
    {
        std::shared_ptr< AbstractIterator > it = getIterator();
        iterators.push_back( it );
        return it;
    }
private:
    virtual std::shared_ptr< AbstractIterator > getIterator() = 0;

private:
    std::list< std::shared_ptr< AbstractIterator > > iterators;
};

class Iterator : public AbstractIterator{
public:
    Iterator( AbstractList* list ) : AbstractIterator(list){}
    ~Iterator() {printf("Iterator cleaned\n");}

    virtual bool moveNext() override
    {
        if( !isValid() )
        {
            return false;
        }

        //do ...... iterate ... whatever

        return true;
    }

    virtual void do_something() override
    {
        printf("hello\n");
    }

};

class List : public AbstractList{
public:
    ~List()
    {
        printf("List cleaned\n");
    }

    List() {}

private:
    std::shared_ptr< AbstractIterator > getIterator() override
    {
        std::shared_ptr< AbstractIterator > iterator( new Iterator( this ) );
        return iterator;
    }
};

int main(int argc, char *argv[])
{
    List* list = new List();

    std::shared_ptr< AbstractIterator > it = list->iterator();
    it->doSomething();
    if( it->isValid() )
    {
        std::cout << "It valid" << std::endl;
    }
    delete list;
    if( !it->isValid() )
    {
        std::cout << "It !valid" << std::endl;
    }

    return 0;
}

这更不像应该是什么样子

【讨论】:

  • 只要 List 类存在或创建新的迭代器(调用 getIterator())就存在。这就是为什么存储为 Iterator 类 btw 的成员的原因。
  • ups 对不起,太快了。今天太热了,不能用大脑。赞成;)
  • 罗伯特,我试图实现的是为单个列表一次拥有多个迭代器。
  • 在那种情况下,恐怕你必须在堆上分配它,因为迭代器的数量是可变的且未知的。此外 1. 将它们保存在列表/地图中 2. 在列表更改附加/删除、列表销毁的情况下管理它们。强烈建议依赖共享指针。只有当每个列表有一个迭代器时,我的示例才合理。但是,这取决于您对该迭代器有什么期望。
  • 你的意思是示例实现?
【解决方案2】:

另一种解决方案可能是:

class AbstractIteratorImpl{
public:
    virtual void do_something() = 0;
};

class Iterator {
pibluc:
    void do_something() { impl->do_something(); }
    friend class AbstractList;
private:
    Iterator( std::unique_ptr<AbstractIteratorImpl> &limpl ) : impl( limpl ){}
    std::unique_ptr<AbstractIteratorImpl> impl;
}

class AbstractList
{
    virtual std::unique_ptr<AbstractIteratorImpl> getIteratorImpl() = 0;
public:
    Iterator getIterator() { return Iterator( getIteratorImpl() ); }
};

我不确定所有参数/返回类型是否正确,但我希望思路清晰。

PS 当然,如果你想在容器中保留迭代器的所有权,你可以使用 std::shared_ptr 加上你可以在 Iterator 中保留 std::weak_ptr 并且你不必显式地实现 invalidate(),那就是自动魔法。

【讨论】:

  • 装饰器模式?非常有趣的方法,我喜欢它
【解决方案3】:

我猜你的意思是对抽象类类型对象的非 const 引用(与 Java 相比,C++ 没有接口,它们只是纯抽象类)。

要返回引用,对象必须在某处保持活动状态。因此,如果您的 AbstractList 是一个接口(仅限抽象方法),我将不知道该怎么做。

【讨论】:

  • 所以指针或智能指针只是解决方案,对象将存在于堆中
  • 不,请不要在不需要的时候使用指针,忘记我的答案(也许我会删除它)并看看罗伯茨。
  • 罗伯特没有出错吗?返回对临时的引用?
  • 另外请不要删除答案,我正准备接受它,只是想'讨论'关于罗伯特的答案完成
  • 乍一看,我以为这是暂时的,但事实并非如此。我的错误是认为您不能在抽象类中拥有该成员。但是,这不是必需的,因为您可以将其存储在具体的 Iterator 中,并且该接口仅提供对它的访问。
猜你喜欢
  • 2012-08-20
  • 1970-01-01
  • 1970-01-01
  • 2014-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多