Nick
Nick

Reputation: 10539

returning reference to class

I have code like this:

#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;
}

This works, but I want to "push" getIterator() method to AbstractList class. To do so, need to be able to do following:

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

Is this possible to be done somehow without dynamic allocation?

Upvotes: 0

Views: 99

Answers (3)

Slava
Slava

Reputation: 44238

Another solution could be:

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() ); }
};

I am not sure all argument/return types are correct, but I hope idea is clear.

PS Of course if you want to keep ownership of the iterator in the container you can use std::shared_ptr plus you may keep std::weak_ptr in Iterator and you would not have to implement invalidate() explicitly, that would be automagic.

Upvotes: 2

Robert Wadowski
Robert Wadowski

Reputation: 1427

Maybe this

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;
}

BTW. It is important to remember about iterator validness ( modification of lists, virtual destructors etc ), this example is very basic :)

This is written very fast

  • invalidation function for iterator should be private, it can be done but it will complicate a little bit source
  • notice that iterface method are called by template method - good habit

Source:

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;
}

This is more less how should look like

Upvotes: 6

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122133

I guess what you mean is a non const reference to an object of abstract class type (in contrast to Java, C++ does not have interfaces, they are just pure abstract classes).

To return a reference, the object has to be kept alive somewhere. Thus, if your AbstractList is an interface (abstract methods only) I would not know how to do it.

Upvotes: 1

Related Questions