I am currently creating a set of iterators which will differ in implementation detail, but will be used in the same algorithms. For this reason, they must all have the same interface. To achieve this, I created an abstract iterator class and inherited from this class in all further iterators.
This should give you an idea of what my code looks like:
class INodeIterator
{
public:
virtual ~INodeIterator() {};
virtual bool operator!= (const INodeIterator& other) =0;
virtual bool operator== (const INodeIterator& other) =0;
virtual INodeIterator& operator++ () =0;
virtual INodeIterator& operator++ (int i) =0;
virtual Node& operator* () =0;
};
class NodeIterator : public INodeIterator
{
public:
/* snip */
NodeIterator& operator++ (int i)
{
NodeIterator tmp(*this);
++(*this);
return(tmp);
}
};
Now I am facing the same problem as in C++ post-increment operator overload in iterators (compiling with -Wall -Werror): My operator++(int) implementation throws a warning (gcc 4.8.0) that a reference to a temporary is returned. The solution in the linked question was to just return the object instead of the reference.
However, this will not work for me. If I change both interface and derived class to return an object instead of a reference, the following errors appear (excerpt, additional file names etc. removed):
INodeIterator.h:16:27: error: invalid abstract return type for member function ‘virtual INodeIterator INodeIterator::operator++(int)’
virtual INodeIterator operator++ (int i) =0;
^
NodeIterator.h:33:22: error: invalid covariant return type for ‘virtual NodeIterator NodeIterator::operator++(int)’
NodeIterator operator++ (int i);
^
INodeIterator.h:16:27: error: overriding ‘virtual INodeIterator INodeIterator::operator++(int)’
virtual INodeIterator operator++ (int i) =0;
^
Changing the return type to object on the derived class but not on the abstract class expectedly returns a "conflicting return type specified" error.
How can I make this work?
Try to change design: let's NodeIterator holds INodeIterator as a pointer. All methods of NoteIterator will delegates to the holding INodeIterator object. In that case you can use correct signature:
struct IteratorInterface {
virtual ~IteratorInterface() {}
virtual std::unique_ptr<IteratorInterface> clone() const = 0;
virtual void next() = 0;
};
class Iterator {
std::unique_ptr<IteratorInterface> impl;
public:
Iterator(std::unique_ptr<IteratorInterface> r) : impl(std::move(r)) {}
Iterator(const Iterator &r) : impl(r.impl->clone()) {}
Iterator& operator++() {
impl->next();
return *this;
}
Iterator operator++(int ) {
Iterator tmp(*this);
impl->next();
return tmp;
}
void swap(Iterator &other) {
other.impl.swap(impl);
}
};
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
struct IteratorInterfaceImpl : IteratorInterface {
int i;
IteratorInterfaceImpl() : i(0) {}
virtual std::unique_ptr<IteratorInterface> clone() const {
return std::unique_ptr<IteratorInterface>(new IteratorInterfaceImpl(*this));
}
virtual void next() {
i += 1;
}
};
Iterator tmp(std::unique_ptr<IteratorInterface>(new IteratorInterfaceImpl()));
tmp++;
++tmp;
return 0;
}
The only sane way I can think of is to return void from INodeIterator::operator++(int) - i.e. nothing.
You can't return a reference from the post-increment operator, because you'll have to create an actual object (storing the previous value) of which you return a reference. This object is either dynamically allocated and would have to be destroyed (had to call delete explicitly on the reference returned) or it is a "local variable" of operator++(int) and will get destroyed before returning:
virtual NodeIterator& operator++(int)
{
NodeIterator prev_value(*this);
++(*this);
return prev_value; // dangling/invalid reference, `prev_value` is destroyed
}
virtual NodeIterator& operator++(int)
{
NodeIterator* pPrev_value = new NodeIterator(*this);
++(*this);
return *pPrev_value; // have to explicitly call delete on the returned ref...
}
You also cannot return an object of type INodeIterator from INodeIterator::operator++(int) because it's an abstract class.
The reason you get the error
INodeIterator.h:16:27: error: invalid abstract return type for member function ‘virtual INodeIterator INodeIterator::operator++(int)’
virtual INodeIterator operator++ (int i) =0;
Is because your pure virtual function returns a abstract class object.
One solution is to use new operator and return the object created in heap, which is safe.
virtual INodeIterator& operator++ (int i) =0;
NodeIterator& operator++ (int i)
{
NodeIterator* tmp = new NodeIterator (*this);
++(*this);
return(*tmp);
}
Your prototype is incorrect. It should be
NodeIterator operator++ (int i)
That is, drop the reference return, otherwise you are returning a reference to something that has gone out of scope (your tmp) Not a good idea!
And the compiler was being very helpful in letting you know this!
Not quite what you wanted to hear I know.
Related
Below I depict the general structure of my code:
class OperandIterator : public std::iterator<std::input_iterator_tag, pOpReference>
{
public:
OperandIterator(...)...
OperandIterator & operator++(); // also calls to advance()
OperandIterator operator++(int); // also calls to advance()
bool operator==(const OperandIterator & other) const;
bool operator!=(const OperandIterator & other) const;
pOpReference operator*();
protected:
virtual void advance();
}
class OperandSpecialIterator : public OperandIterator
{
public:
...
private:
void advance() override; // this is the only diffrence between the classes
}
class TraversalPattern
{
public:
TraversalPattern(Operand op, Order order, bool specialTraversal);
OperandIterator begin() { return specialTraversal ? OperandSpecialIterator(...) : OperanInerator(...); }
}
// somewhere
TraversalPattern p(...specialTraversal=ture);
OperandIterator iter = p.begin();
it++;
Even though begin() function returns OperandSpecialIterator, when it++ performed the advance function that is being called is the advance function of OperandIterator.
The problem is that begin() can't return a reference.
The question is:
Can begin function return iterators of different types?
What you are asking is not possible. The begin() function cannot return different types depending on a runtime value. What you could do, is implement something like a VariantIterator that can hold different types of operators in an std::variant (C++17) and forwards the iterator operations to the currently held iterator.
For this simple case, I personally would do the advancing by passing a function pointer to my Iterator:
class OperandIterator; // forward declaration
namespace advancers { // Forward declarations since definition only works,
// when OperandIterator is defined. You can make this easier by making
// these methods static in the class. I declare them forward to be able
// to use them as defaults in OperandIterator.
void advance_normally(OperandIterator& it);
void advance_specially(OperandIterator &it);
} // End namespace advancers
class OperandIterator : public std::iterator<std::input_iterator_tag, pOpReference>
{
public:
OperandIterator() = default;
OperandIterator(void (*advanc_fnc)(OperandIterator&)) : advancer(advanc_fnc) {}
OperandIterator & operator++(); // also calls advancer with *this
OperandIterator operator++(int); // also calls advancer with *this
private:
const void (*advancer)(OperandIterator&) = &advancers::advance_normally;
}
namespace advancers { // Definitions
void advance_normally(OperandIterator& it) {
it++;
}
void advance_specially(OperandIterator &it) {
// Something else
}
} // End namespace advancers
OperandIterator make_special() {
return OperandIterator(&advancers::advance_specially);
}
class TraversalPattern
{
public:
TraversalPattern(Operand op, Order order, bool specialTraversal);
OperandIterator begin() { return specialTraversal ? OperandSpecialIterator() : make_special(); }
}
// somewhere
TraversalPattern p(...specialTraversal=ture);
OperandIterator iter = p.begin();
it++;
The nice thing about this is, that you can easily add more versions of advancing and even make them in place with a lambda.
I'm actually new to c++. I mostly worked with Java.
I tried to build my own iterator, and after a bit of reading, came up with this method.
template<class T> class Iterable
{
T start,stop;
public:
explicit Iterable(T s,T e) {start=s; stop=e;}
public:
virtual void next(T& i);
public:
class iterator: public std::iterator<
std::input_iterator_tag, // iterator_category
T, // value_type
long, // difference_type
const T*, // pointer
T // reference
>{
T current;
Iterable<T>& obj;
public:
explicit iterator(T t,Iterable<T>& o) : obj(o) {current=t;}
iterator& operator++() {obj.next(current); return *this;}
iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
bool operator==(iterator other) const {return current == other.current;}
bool operator!=(iterator other) const {return !(*this == other);}
T operator*() const {return current;}
};
iterator begin() {return iterator(start,*this);}
iterator end() {return iterator(stop,*this);}
};
class Range : public Iterable<long>
{
long START,STOP;
public:
void next(long& cur) override
{
if(START>=STOP)
cur++;
else
cur--;
}
public:
Range(long st,long en) : Iterable(st,en) {START=st; STOP=en;}
};
This is my "flex.h" header file. The header compiles OK.
However, when I try to use this Range class, I get the error:
undefined reference to `flex::Iterable<long>::next(long&)'
collect2: error: ld returned 1 exit status
in my compiler (I use g++)
My Test1.cpp file is as follows:
(After includes)
int main()
{
Range range=Range(15,10);
for(auto r : range)
cout << r << "\n";
}
Could someone explain where I went wrong, and how this can be fixed?
Thanks.
You declare a virtual function in next, and don't define it.
A virtual member function has to be defined, be pure virtual, or both. So if you declare
virtual void next(T& i);
It must be defined either inline or outside the class definition because it is not pure virtual. If you intended to make Iterable a template for abstract classes, then adding the pure virtual specifier to next will absolve the error.
virtual void next(T& i) = 0;
I've searched before asking but din't found anything working for my problem.
I would like to make a pointer to superclass (that really always refers to one of the subclasses) match a subclass argument (pointer or const reference) in a function.
Context : create an "advanced" calculator in c++.
Let me give you more details the classes being used in this issue of mine :
First we have the Literals :
class Literal {};
class IntegerLiteral : public Literal {};
class RealLiteral : public Literal {};
class RationalLiteral : public Literal {};
//....
We have a stack used to save the Literal objects by storing their adresses
// If st is instance of stack then :
st.top(); // returns a Literal*
And we have Operator objects that will interact with the stack by unstacking the correct numbers of Literal* (depending on the operator's arity), applying the operator on the Literal* objects and finally stack the result.
class Operator {
int n; // operator arity
public:
virtual void executeOperator(stack *st) = 0; //
};
One of the Operator subclass (for example) :
class PlusOperator : public Operator {
public:
virtual void execute(StackUTComputer *st) override {
Literal* arg1 = st->top();
Literal* arg2 = st->top();
Literal* result = applyOperator(arg1, arg2);
st->pop(); st->pop();
st->push(result);
}
Literal* execute(IntegerLiteral* a, IntegerLiteral* b) {
return new IntegerLiteral(a->getValue() + b->getValue());
}
Literal* execute(IntegerLiteral* a, RealLiteral* b) {
return new RealLiteral(a->getValue() + b->getValue());
}
Literal* execute(IntegerLiteral* a, RationalLiteral* b) {
return new RationalLiteral(
a->getValue() + (a->getValue()*b->getDenominator()),
b->getDenominator()
);
}
// ...
};
My purpose here (by overloading the function applyOperator) is to "magically" let the computer know which function call depending on the real type of Literal unstacked by the operator (the class Literal is abstract : the stack will always contain specifics Literal's subclasses).
But it does not work the way I want.
I mean that the call applyOperator(arg1, arg2) (with arg1 and arg2 being Literal*) is invalid because no functions match the signature.
I'm aware that I kind of use the c++ polymorphism int the other way that it's normally used (that is give a subclass argument to a function that take a superclass argument).
I don't know how to turn around my architecture in order to properly use the polymorphism et maybe there is some syntax helpful solution in order to make my idea work.
Either way, I'm grateful for your help !!
Raphael.
There is a way to do it with polymorphism as intended (without dynamic_cast):
#include <iostream>
#include <memory>
#include <string>
struct IntegerLiteral;
struct RealLiteral;
struct Literal {
virtual void add(const Literal &) = 0;
virtual void add(const IntegerLiteral &) = 0;
virtual void add(const RealLiteral &) = 0;
virtual void add_to(Literal &) const = 0;
virtual void add_to(IntegerLiteral &) const = 0;
virtual void add_to(RealLiteral &) const = 0;
virtual std::ostream &print(std::ostream &os) const = 0;
virtual ~Literal() = default;
};
std::ostream &operator<<(std::ostream &os, const Literal &l) {
return l.print(os);
}
struct IntegerLiteral : Literal {
IntegerLiteral(int i)
: i(i) {}
int i = 0;
void add(const Literal &other) override {
//now we know one operand is an IntegerLiteral and can pass on that information to the other Literal
other.add_to(*this);
}
void add(const IntegerLiteral &other) override {
i += other.i;
}
void add(const RealLiteral &other) override;
void add_to(Literal &other) const override {
other.add(*this);
}
void add_to(IntegerLiteral &other) const override {
other.i += i;
}
void add_to(RealLiteral &other) const override;
std::ostream &print(std::ostream &os) const override {
return os << i;
}
};
struct RealLiteral : Literal {
RealLiteral(double d)
: d(d) {}
double d = 0;
void add(const Literal &other) override {
other.add_to(*this);
}
void add(const IntegerLiteral &other) override {
d += other.i;
}
void add(const RealLiteral &other) override {
d += other.d;
}
void add_to(Literal &other) const override {
other.add(*this);
}
void add_to(IntegerLiteral &other) const override {
//now we know both operands and can do the calculation
other.i += d;
}
void add_to(RealLiteral &other) const override {
other.d += d;
}
std::ostream &print(std::ostream &os) const override {
return os << d;
}
};
void IntegerLiteral::add(const RealLiteral &other) {
i += other.d;
}
void IntegerLiteral::add_to(RealLiteral &other) const {
other.d += i;
}
int main() {
std::unique_ptr<Literal> l1 = std::make_unique<RealLiteral>(3.14);
std::unique_ptr<Literal> l2 = std::make_unique<IntegerLiteral>(42);
l1->add(*l2);
std::cout << *l1 << '\n';
}
DEMO
You need a ton of code to make this work and it gets quadratically worse with every Literal you add and twice as bad with every operator. Also if you forget to override a function you are likely to get an infinite loop and a stack overflow at run time.
A much better approach (easier to write and faster to run) would be to just use double or BigNum for everything and not bother with polymorphism.
You are mixing different concepts, which are ad hoc polymorphism (overloads) and subtype polymorphism, which in is implemented through late binding of methods through virtual tables.
Basically what happens is that the compiler chooses which overloaded method to call at compile time, not at runtime. This makes impossible what you are trying to do without using RTTI.
The compiler is not able to determine which will be the type of the two Literal instances, and C++ supports only early binding when dealing with non virtual methods. The only thing that it can deduce at compile time is the fact that both arguments are of type Literal* so it looks for that overload only.
You need a sort of dynamic switch to do what you want, which can be obtained through the use of dynamic_cast (or similar hand made solutions).
So in the interest of creating a Minimal. Complete, Verifiable Example I have created a toy iterator here (I know it's not perfect, it's just for the purposes of asking a question):
class foo : public iterator<input_iterator_tag, string> {
string _foo;
static const size_t _size = 13;
public:
const string& operator*() { return _foo; }
const foo& operator++() {
_foo += '*';
return *this;
}
const foo operator++(int) {
auto result = *this;
_foo += '*';
return result;
}
bool operator==(const foo& rhs) { return _foo.empty() != rhs._foo.empty() && _foo.size() % _size == rhs._foo.size() % _size; }
bool operator!=(const foo& rhs) { return !operator==(rhs); }
};
I read that an InputIterator needs to have defined the Member Selection Operator. The Indirection Operator makes sense, but a Member Selection Operator is confusing to me here. How would an Member Selection Operator be implemented for foo?
const string* operator->() const { return &_foo; }
Example usage:
foo i;
++i;
assert(i->length() == 1);
The way this works is that the compiler will generate repeated calls to operator-> until the return type is a raw pointer (so in this case just one call to foo::operator->), then do the regular member selection operation on that pointer.
The operator->() should return a pointer type of the type the container holds that the iterator is used on. So if you have a container that holds a std::string then the iterator::operator-> should return a std::sting*. In your case since you derive from std::iterator you can use the pointer typedef for the return type.
My requirements are same to the question asked Using Iterators to hide internal container and achieve generic operation over a base container[1] at stackoverflow. I have a generic pure virtual base container class, which needs to provide an iterator which should be STL complaint so I can use them with cpp algorithm's #include <algorithm>. My implementation uses only an single class instead of two classes as in [1] solution.
Base pure virtual class
class BaseItr
{
public:
class iterator : public std::iterator<std::input_iterator_tag, int>
{
public:
iterator() : _in(NULL) {}
inline iterator(const iterator& org) : _in(org._in) {}
inline iterator& operator=(const iterator& other) { _in = other._in; return *this; }
virtual inline int operator * () { return _in->operator*(); }
virtual inline iterator& operator++() { (*_in)++; return *this; }
virtual inline iterator& operator++(int unused) { (*_in)++; return *this; }
virtual inline bool operator==(const iterator& other)
{
return *(*_in) == *(*(other._in));
}
virtual inline bool operator!=(const iterator& other)
{
return *(*_in) != *(*(other._in));
}
// would use shared pointer insted of this
//~iterator() { if(_in) { delete _in; } }
static inline iterator New(iterator *in) { return iterator(in); }
private:
iterator(iterator *in) : _in(in) {}
iterator *_in;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
};
Implementation
class Itr : public BaseItr
{
private:
class iterator : public BaseItr::iterator
{
public:
iterator(int val) : _val(val), BaseItr::iterator() {}
int operator * () { return _val; }
inline iterator& operator++() { ++_val; return *this; }
inline iterator& operator++(int unused) { _val++; return *this; }
private:
int _val;
};
BaseItr::iterator _begin;
BaseItr::iterator _end;
public:
inline Itr(int start, int end)
{
_begin = BaseItr::iterator::New(new iterator(start));
_end = BaseItr::iterator::New(new iterator(end));
}
BaseItr::iterator begin() { return _begin; }
BaseItr::iterator end() { return _end; }
};
My implementation works was need, I want to know are there any drawbacks with this implementation, Please help me decide with my design to use the appropriate implementation. I have add my full working example code in github:gist https://gist.github.com/3847688
Ref:
Iterator for custom container with derived classes
Using Iterators to hide internal container and achieve generic operation over a base container
Fast and flexible iterator for abstract class
C++ : Using different iterator types in subclasses without breaking the inheritance mechanism
The most glaring issue: your iterator does not have value semantics.
The STL algorithms are free to copy an iterator if they wish. For example suppose:
template <typename It>
It find(It b, It e, typename std::iterator_traits<It>::const_reference t) {
for (; b != e; ++b) {
if (*b == t) { return b; }
}
return e;
}
The problem is that if you invoke this algorithm with BaseItr&, then the result is of type BaseItr, and you are thus exposed to Object Slicing, which is undefined behavior.
In order to give value semantics to you iterator, you need to create a wrapper class around an abstract implementation and have the wrapper correctly manage the copy through a virtual clone method. If your iterator ends up with virtual methods, you are doing it wrong.