0

I have a class called Base which holds internally a container of objects of type SomeType. Then I create class Derived: protected Base.

Now I want to create custom iterators in the Derived class to offer the user the ability to iterate over the objects in the container in the Base class. The thing is that SomeType offers more features that I want to give i.e. I want to hide some of the functions offered in SomeType and possibly add some extra data fields and functions.


So one thing I tried to do is wrap SomeType like this:

class AnotherType{
    private:
        SomeType& object;
    public:
    //Make visible what I want
}

And then inside the operator*() in the iterator create a new AnotherType object and return it.

My problem with this is that then, I can't do this:

Derived d;
for(auto& object: d)
    // Use object however i like.

Note the "&" in auto.

One other possible solution, in the case that I won't add any extra data fields, would be to use something like this. But as I see it is undefined behaviour.

Any ideas?

Community
  • 1
  • 1
user183833
  • 228
  • 1
  • 8
  • So your problem is that you want to inhibit the object, but than you can't use it uninhabited? – StoryTeller - Unslander Monica Oct 26 '16 at 13:39
  • Can you provide some mcvs example? – foxfireee Oct 26 '16 at 13:42
  • @StoryTeller I want to hide a part of `SomeType`'s interface but the main solution that I came up with, to do this, creates that particular problem. – user183833 Oct 26 '16 at 13:44
  • Is there any particular reason you want to use `for(auto& object: d)` instead of just `for(auto object: d)`? – Altainia Oct 26 '16 at 13:45
  • @Altainia Well, at least I, generally, tend to use a lot the first one, because I either want to make some mutations, or I dont want to make unnecessary copies. And I believe many other people do so. So I don't want to pop errors in someone's code if he uses my classes in the first way. It would be pretty strange wouldn't it? – user183833 Oct 26 '16 at 13:50
  • 1
    @user183833 If your `AnotherType` is simply a wrapper around `SomeType` to restrict functionality and it already contains a reference to a `SomeType` object, you'll be able to mutate the underlying `SomeType` object without grabbing an `AnotherType` by reference. As far as copying, depends. Again, if all `AnotherType` has is a reference to `SomeType`, copying is a simple matter. – Altainia Oct 26 '16 at 13:57
  • @Altainia I agree with all that you write, my only problem is inconsistency and that it makes the API strange. One user would generally expect the ranged for loop to work with the "&". Also he would expect that if he does not put an "&" in the loop then the mutations he makes are not in the objects inside the container but in the copies that are made for the loop. – user183833 Oct 26 '16 at 14:06
  • @foxfireee I don't know what mcvs means. – user183833 Oct 26 '16 at 14:19
  • sorry, mcve is described here: [http://stackoverflow.com/help/mcve] – foxfireee Oct 27 '16 at 06:30

1 Answers1

1

Since it is your desire for the iterator to return references, you need to have a non-temporary object that you can return a reference to. The easiest way to do that would be to have your iterator class contain an instance of AnotherType, and have the member of AnotherType be an iterator of Base rather than a reference so that it can be updated when the Derived iterator is modified.

class AnotherType{
    private:
        Base::iterator iter;
    public:
        AnotherType(Base::iterator it) : iter(it) { }
    //Make visible what I want
        void Foo() { iter->Foo(); }
};
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • The reason I hesitated to go this way is because: for example if the user while iterates in a range for loop and possibly keeps a pointer to a previous dereferenced iterator value, it will be "invalid" in the next repetitions, as now in that memory is being stored the lastest value. This essentially follows the [input iterator semantics](http://en.cppreference.com/w/cpp/concept/InputIterator). Nevertheless thanks for your input, in the end, if nothing better comes up it's either this or my first initial choice. – user183833 Oct 27 '16 at 07:51