I have created an interface class which defines a Queue for Childpointers.
class IChildQueue
{
public:
IChildQueue(void) {};
virtual ~IChildQueue(void) {};
public:
virtual bool add(ChildProcess *oChildProcess) = 0;
virtual void remove(ChildProcess *oChildProcess) = 0;
virtual void clear(void) = 0;
virtual unsigned int size(void) = 0;
virtual const IChildQueueIterator &begin(void) = 0; <-- this is the problem
};
Now I wanted to add an iterator to the interface so that a client can iterate over the childs without messing with the queue itself.. As my knowledge of C++ is not THAT good, I didn't manage to get this working.
My goal was what I can use the iterator conveniently in a for loop, so it should have autostorage duration and it should act as a proxy to the underlying object. i.E. like this:
for(Iterator it = master.begin(); it != it.end(); ++it)
it->childfunction(); <-- by overloading the -> operator.
And No, I don't want to use boost for various reasons.
So far my Iterator looks like this:
class IChildQueueIterator
{
public:
IChildQueueIterator(IChildQueue *pQueue);
virtual ~IChildQueueIterator() {};
virtual ChildProcess *operator->() const = 0;
virtual bool operator==(IChildQueueIterator const &lhs) = 0;
virtual bool operator!=(IChildQueueIterator const &lhs) = 0;
virtual ChildProcess &operator++() = 0;
virtual const ChildProcess operator++(int) = 0;
virtual bool end(void) = 0;
};
I'm not sure if this even possible, but I would at least like to know why, if this is indeed the case.
Related
I got interface IDocument and ConcreteDocument implementing it. I want to allow users to iterate through any concrete document, so Im tried to add begin() and end() members in interface.
IDocument:
virtual R begin() const noexept = 0;
R must be concrete T that given by template Interface parameter or method's template parameter (impossible for virtual methods).
What R should be?
I tried to use templates for interface, but its a bad idea, bc clients now knows what ContainerT ConcreteDocument is using.
I tried to use std::iterator, but my ConcreteDocument e.g. uses std::deque<T>, so convertion between std::iterator and std::deque<T>::{const_iterator|iterator} is undefined
Any ideas?
Upd:
Ok, std::iterator is deprecated
Code example:
class IDocument
{
public:
using Path = StdPath;
virtual void InsertItem(const ItemT&
std::optional<size_t> position = std::nullopt)
= 0;
virtual size_t GetItemsCount() const = 0;
virtual const DocumentItem& GetItem(size_t index) const noexcept = 0;
virtual void DeleteItem(size_t index) = 0;
virtual const std::string& GetTitle() const = 0;
virtual void SetTitle(const std::string& title) = 0;
// `begin()` `end()` methods, but how signature looks like if i don't know what concrete container is used by derived classes?
virtual ~IDocument() = default;
};
class HTMLDocument : public IDocument
{
public:
HTMLDocument() = default;
template <typename StringT = std::string>
HTMLDocument(StringT&& string)
: m_title(std::forward<StringT>(string))
, m_undoManager()
{
}
size_t GetItemsCount() const final;
const DocumentItem& GetItem(size_t index) const noexcept final;
void DeleteItem(size_t index) final;
const std::string& GetTitle() const final;
void SetTitle(const std::string& title) final;
void Save(const StdPath& path) const final;
// here need `begin()` and `end()` methods accessable through IDocument*
private:
std::string m_title = "Title";
std::deque<DocumentItem> m_items;
UndoManager m_undoManager{};
};
I need to implement non-member function that outputs Document's content into std::ostream&
So, for more handy-usage I want begin() and end() methods in interface, but I can't figure out whats their signatures are, bc they are based on ContainerT
I want to start throwing some interfaces into my C++ code to make it easier for me to unit test using mocks.
The problem with this is returning abstract classes from a method in C++ is a pain. You can't return by value so you need to return a pointer or a reference.
Given all of the developments in C++ in the last six or seven years, I thought I'd ask if maybe we had a better way to return an abstract base class. An interface without the noise would look something like this, but I'm sure this isn't possible.
IBaseInterface getThing() {return DerivedThing{};}
The way that I remember doing this in the past is to use a pointer (probably a smart pointer now):
std::unique_ptr<IBaseInterface> getThing() {return std::make_unique<DerivedThing>();}
The problem with the pointer is that I'm never actually planning to take advantage of nullptr so the overhead and noise of dealing with a pointer rather than a value gains me no value as a reader.
Is there a better way that I don't know to handle this?
EDIT: provides complete example, including making the polymorphic handle copyable.
#include <iostream>
#include <utility>
#include <memory>
struct IBaseInterface {
IBaseInterface() = default;
IBaseInterface(IBaseInterface const&) = default;
IBaseInterface(IBaseInterface &&) = default;
IBaseInterface& operator=(IBaseInterface const&) = default;
IBaseInterface& operator=(IBaseInterface &&) = default;
virtual ~IBaseInterface() = default;
virtual std::unique_ptr<IBaseInterface> clone() const = 0;
virtual void do_thing() = 0;
};
struct handle
{
handle(std::unique_ptr<IBaseInterface> ptr)
: _impl(std::move(ptr))
{}
handle(handle const& r)
: _impl(r._impl->clone())
{}
handle(handle && r)
: _impl(std::move(r._impl))
{}
handle& operator=(handle const& r)
{
auto tmp = r;
std::swap(_impl, tmp._impl);
return *this;
}
handle& operator=(handle && r)
{
_impl = std::move(r._impl);
return *this;
}
// interface here
void do_thing() { _impl->do_thing(); }
private:
std::unique_ptr<IBaseInterface> _impl;
};
struct DerivedThing : IBaseInterface
{
std::unique_ptr<IBaseInterface> clone() const override
{
return std::make_unique<DerivedThing>(*this);
}
void do_thing() override
{
std::cout << "I'm doing something" << std::endl;
}
};
handle make_thing()
{
return handle(std::make_unique<DerivedThing>());
};
int main()
{
auto a = make_thing();
auto b = a;
a.do_thing();
b.do_thing();
return 0;
}
Now use your handle as if it had (moveable) value semantics
Apologies that this is pretty long, but I couldn't figure out how to make it shorter and still show the important features of my problem.
I'm asking this even though I have come up with an idea of how to do what I want, but it requires implementing an iterator in a way that doesn't match the standard iterator pattern. I would like to ask for any suggestions on how this could be done in a more standard or better way.
I have an abstract base class. Any subclass of it will have some collections of objects. There is some common code that I would like to put in the base class that needs to iterate over all of the objects in the collections. The objects in the collections will all descend from another abstract base class, but will be subclass objects. There may be multiple collections of objects from multible subclasses, and the collections may be different collection types. What I'd really like to do is something like this: (Note: this code will not compile.)
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool operator!=(iterator& other) = 0;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
int processCollections()
{
iterator it;
int sum = 0;
for(it = begin(); it != end(); ++it)
{
sum += (*it).someInterface(7);
}
return sum;
}
};
And then I want some subclasses of CollectionObjectBase and MyObjectBase like this:
class CollectionObject1 : public CollectionObjectBase { ... }
class CollectionObject2 : public CollectionObjectBase { ... }
class CollectionObject3 : public CollectionObjectBase { ... }
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::vector< CollectionObject2>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
class MyObjectB : public MyObjectBase
{
public:
std::vector<CollectionObject1> someThings;
std::set< CollectionObject3> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::vector<CollectionObject1>::iterator it1;
std::set< CollectionObject3>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
There are some big problems with the above code. First, MyObjectBase::begin() and MyObjectBase::end() can't return MyObjectBase::iterator because MyObjectBase::iterator is an abstract class, and you wouldn't want to anyway because you actually want a subclass of MyObjectBase::iterator that knows how to iterate over the collections in the subclass of MyObjectBase. You need to return a reference to MyObjectBase::iterator.
The second problem comes with MyObjectA::iterator::operator!=(). You'd like to do something like this:
virtual bool operator!=(iterator& other)
{
return it1 != other.it1 || it2 != other.it2;
}
But to be an overload of MyObjectBase::iterator::operator!=() it has to take a parameter of type MyObjectBase::iterator& and that doesn't have members it1 and it2. My best idea I've thought of to resolve this is to replace operator!=() with a function atEnd(), since the only thing it is being used for in this code is to detect if the iterator is at the end, but it makes it really non-standard.
Finally, MyObjectA::begin() and MyObjectA::end() cannot return a temporary. Remember, we have to return a reference to a MyObjectBase::iterator that points to a MyObjectA::iterator, not copy construct a MyObjectBase::iterator. My best idea I've thought of to resolve this is to allocate the iterator with new, and when I do that I need to return a pointer, not a reference so that the caller can delete it. So here's my final code. It works and performs the function of an iterator, but it is non-standard. Can anyone think of a way to do this with an iterator that fits the standard pattern?
#include <map>
#include <vector>
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool atEnd() = 0;
};
virtual iterator* begin() = 0;
int processCollections()
{
iterator* it;
int sum = 0;
for (it = begin(); !it->atEnd(); ++it)
{
sum += (**it).someInterface(7);
}
delete it;
return sum;
}
};
class CollectionObject1 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 1;
}
};
class CollectionObject2 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 2;
}
};
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::map<int, CollectionObject1>::iterator it1End;
std::vector< CollectionObject2>::iterator it2;
std::vector< CollectionObject2>::iterator it2End;
iterator(std::map<int, CollectionObject1>::iterator it1Init, std::map<int, CollectionObject1>::iterator it1EndInit,
std::vector< CollectionObject2>::iterator it2Init, std::vector< CollectionObject2>::iterator it2EndInit) :
it1(it1Init),
it1End(it1EndInit),
it2(it2Init),
it2End(it2EndInit)
{
// Initialization handled by initialization list.
}
virtual CollectionObjectBase& operator*()
{
if (it1 != it1End)
{
return (*it1).second;
}
else
{
return *it2;
}
}
virtual iterator& operator++()
{
if (it1 != it1End)
{
++it1;
}
else
{
++it2;
}
return *this;
}
virtual bool atEnd()
{
return it1 == it1End && it2 == it2End;
}
};
virtual MyObjectBase::iterator* begin()
{
return new iterator(someThings.begin(), someThings.end(), otherThings.begin(), otherThings.end());
}
};
There's an issue with useless' answer. Consider these subclasses of Impl and Base:
class MyImpl : public Base::Iterator::Impl {
public:
MyImpl(std::vector<CollectionObjectSub>::iterator itInit) : it(itInit) {}
CollectionObjectBase& operator*() { return *it; }
void operator++() { ++it; }
// bool operator==(Base::Iterator::Impl const &other) const { it == other.it; }
bool operator==(MyImpl const &other) const { it == other.it; }
private:
std::vector<CollectionObjectSub>::iterator it;
};
class Sub : public Base {
public:
Iterator& begin() { return Iterator(new MyImpl(collection.begin())); }
private:
std::vector<CollectionObjectSub> collection;
};
Sub contains a vector and MyImpl contains a vector iterator. I'd like to instantiate a Base::Iterator with impl_ pointing at a MyImpl. If MyImpl::operator== takes a MyImpl& then it isn't overloading Base::Iterator::Impl::operator==, but if it takes a Base::Iterator::Impl& then I can't access the vector iterator even if it actually is a MyImpl.
It seems like I need to do a dynamic cast to get a MyImpl, which requires RTTI. I've heard to avoid using RTTI if possible. Is there another way?
So, you want to return an iterator by value, but have its dynamic type vary depending on the override of begin/end you called? No problem - just add another layer of indirection.
class Base {
public:
class Iterator {
public:
struct Impl {
virtual ~Impl() {}
virtual CollectionObjectBase& operator*() = 0;
virtual void operator++() = 0;
virtual bool operator==(Iterator::Impl const &other) const = 0;
};
Iterator() {}
explicit Iterator(std::unique_ptr<Impl> &&i) : impl_(std::move(i)) {}
Iterator(Iterator &&other) = default;
CollectionObjectBase& operator*() { return **impl_; }
Iterator& operator++() { ++*impl_; return *this; }
bool operator==(Iterator const &other) const {
return (!impl_ && !other.impl_) || (*impl_ == *other.impl_);
}
private:
std::unique_ptr<Impl> impl_;
};
// ...
This uses the pointer-to-impl (pimpl) idiom to give each concrete subclass of Base its own concrete subclass of Base::Iterator::Impl, but still let you pass Base::Iterator objects around by value using move semantics to transfer ownership of the dynamic object.
NB. I made two default-constructed (nullptr) iterators compare equal so you don't need to create a real instance for end.
I'm writing a class which will iterate over a set of handles. Basically I'm working against a bunch of C functions which implement the following interface:
SomeHandle getFirst(ParentHandle);
SomeHandle getNext(SomeHandle);
Here is my iterator's interface and its partial implementation. I need an interface so that I can Mock this iterator for the purposes of TDD.
template<class HandleT>
class IHandleIterator
{
public:
virtual void operator++() = 0;
virtual const HandleT& operator*() const = 0;
};
template<class HandleT>
class HandleIterator : public IHandleIterator<HandleT>
{
public:
// used by something.end()
HandleIterator() : _isLast(true)
{
}
// updates _isLast when the end is reached
virtual void operator++()
{
}
virtual const HandleT& operator*() const
{
return _currentHandle;
}
protected:
HandleT _currentHandle;
bool _isLast;
};
What I want to do is add operator!= to the interface to test when I've reached the end of what I'm iterating over, as follows:
for(IHandleIterator i=something.begin(); i!=seomething.end(); i++)
{
*i;
}
However I can't figure out how to do this. Can anyone offer me suggestions?
If I can't find a solution involving operator!= then I'm wondering if this is a good approach:
class IHandleIterator
{
public:
virtual void operator++() = 0;
virtual const HandleT& operator*() const = 0;
virtual bool isLast const = 0;
};
for(IHandleIterator i=something.begin(); !i.isLast(); i++)
{
*i;
}
What do you think?
I am porting this code from Visual C++ 6.0 (it also worked with an older GCC++) to Visual Studio 2010 C++. The code compiles but throws an exception.
I have an base class, CncMatchedQueryAtom. This class is used contain matches of different types of target atoms (this is a graph matching application) for 99% of the cases there is a one to one match between the query and the target. This is handled by the derived class, CncMatchedQueryAtomSimple. This class works great. The problem is that some query atoms match groups of atoms, this is handled by the class, CncMatchedQueryAtomGroup. This class contains a vector with the matched atoms. I want the iterator class defined within the base class to encapsulate the vector iterator in the derived class such that begin() returns the vector begin() and the end returns the vector's end().
The old version has problems on the end() at runtime because it does the conversion by:
return &*group.end();
Which is no longer allowed by Visual C++
So how can a base class specify an iterator that derived classes can implement? This doesn't seem very obvious to me, but I'm new to C++. Nor is it something that seasoned C++ developers that I work with know of either.
Basically, I want the base class to have methods that provide begin and end functions that the derived classes implement.
Here is the code:
class CncMatchedQueryAtom
{
protected:
int notBlockAllocated;
public:
int allocateIndividually() const
{
return notBlockAllocated;
}
const CncAtom *queryAtom;
CncAtom *queryAtomVolitile() const
{
return (CncAtom*)queryAtom;
}
// set when the class has been allocated by newing
// intialize all default constructors to be notBlockAllocated
CncMatchedQueryAtom()
: notBlockAllocated(1)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
CncMatchedQueryAtom(int noBlock)
: notBlockAllocated(noBlock)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
// may not need this now that it's a virtual!
CncMatchedQueryAtom(const CncMatchedQueryAtom &that)
: queryAtom(NULL)
{
*this = that;
}
// this needs to be virtual so when delete CncMatchedQueryAtom is called
// the virtual calss members are destructed too
virtual ~CncMatchedQueryAtom()
{
}
virtual void dump() const =0;
virtual void clearMapping() =0;
virtual CncMatchedQueryAtom *newCopy() const =0;
virtual void coverHits(class CncTarget *) const = 0;
// iterates over all matched target atoms for this query atom
class iterator
{
private:
CncMatchedTargetAtom *ptr;
public:
iterator()
{
}
iterator(const CncMatchedTargetAtom *targetAtom) // constructor from a target ptr
:ptr((CncMatchedTargetAtom *)targetAtom)
{
}
iterator(const iterator &oldOne)
:ptr(oldOne.ptr)
{
}
~iterator()
{
}
int operator==(const iterator &that) const
{
return ptr==that.ptr;
}
int operator!=(const iterator &that) const
{
return ptr!=that.ptr;
}
const CncMatchedTargetAtom &operator*() const
{
return *ptr;
}
iterator operator++(int NotUsed) // post increment
{
iterator returnValue(*this);
++ptr;
return returnValue;
}
iterator &operator++() // pre increment
{
++ptr;
return *this;
}
int operator<(const iterator &rhs) const
{
return (this->ptr < rhs.ptr);
}
CncMatchedTargetAtom *operator->()
{
return ptr;
}
};
virtual iterator begin() const =0;
virtual iterator end() const =0;
virtual int size() const = 0;
virtual double molecularWeight() const = 0;
const CncAtom *getFirstTargetAtom() const
{
return (*begin()).matchedTargetAtom;
}
CncAtom *getFirstTargetAtomVolitile() const
{
return (CncAtom*)getFirstTargetAtom();
}
}; // class CncMatchedQueryAtom
class CncMatchedQueryAtomSimple : public CncMatchedQueryAtom
{
public:
// we need a constructor here since this is allocated with blockAlloc
CncMatchedQueryAtomSimple()
: CncMatchedQueryAtom(0)
{
}
// we use simple.targetAtom as a temporary variable
// used to pass to matching functions
CncMatchedTargetAtom simple;
void clearIt()
{
queryAtom=NULL;
notBlockAllocated=0;
}
// if queryAtom is an element-type atom (or Lp or A atom)
void dump() const;
void clearMapping()
{
}
CncMatchedQueryAtom *newCopy() const
{
// since this is usually not allocatedIndividually I'll set
// the notBlockAllocatedFlag on the copy to be sure if this
// does happen it will individually deallocate it
CncMatchedQueryAtomSimple *retVal = new CncMatchedQueryAtomSimple(*this);
retVal->notBlockAllocated = 1;
return (CncMatchedQueryAtom *)retVal;
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &simple;
}
iterator end() const
{
return &simple+1;
}
int size() const
{
return 1;
}
double molecularWeight() const
{
return CncMolGetAtomicMassAve(simple.matchedTargetAtom->getAtomicNumber());
}
}; // class CncMatchedQueryAtomSimple
class CncMatchedQueryAtomGroup : public CncMatchedQueryAtom
{
public:
// if queryAtom is an R- or X-group searching for
std::vector<CncMatchedTargetAtom> group;
void dump() const;
void clearMapping()
{
group.clear();
}
CncMatchedQueryAtom *newCopy() const
{
return new CncMatchedQueryAtomGroup(*this);
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &*group.begin();
}
iterator end() const
{
// this is a hack, works with Visual C++ 6.0 and older GCC++ but not VS C++ 2010
return &*group.end(); // Throws error at runtime! Iterator Not Dereferencable
}
int size() const
{
return group.size();
}
double molecularWeight() const
{
double sum=0;
std::vector<CncMatchedTargetAtom>::const_iterator q;
for (q=group.begin()
; q!=group.end()
; ++q)
{
sum += CncMolGetAtomicMassAve(q->matchedTargetAtom->getAtomicNumber());
}
return sum;
}
}; // class CncMatchedQueryAtom
An example of how the iterator is called:
// Sample call to the iterator
// (*elem)->getMatchedAtom() returns a CncMatchedQueryAtom *
CncMatchedQueryAtom::iterator atomMatched;
// welp it looks like we have to do these
//(*elem)->getFirstTargetAtom
for (atomMatched=(*elem)->getMatchedAtom()->begin()
; atomMatched!=(*elem)->getMatchedAtom()->end() // Runtime exception here!
; ++atomMatched)
{
existenceFingerprint.setBit(
atomMatched->matchedTargetAtom->indexInStructure);
}
Thanks, hopefully this isn't too much code...
You cannot convert iterators from one container into iterators to another container.
It used to work with VC6, because they happened to use a pointer as vector::iterator. Later versions have an iterator class where the conversion does not work.