nested classes: not in-class, building iterators updated accordingly

This commit is contained in:
Frank B. Brokken 2019-02-24 14:33:18 +01:00
parent b2e5f30ed4
commit c1a175cff5
3 changed files with 115 additions and 63 deletions

View file

@ -9,40 +9,44 @@
class StringPtr: public std::vector<std::string *>
{
public:
class iterator: public
std::iterator<std::random_access_iterator_tag, std::string>
{
friend class StringPtr;
std::vector<std::string *>::iterator d_current;
iterator(std::vector<std::string *>::iterator const &current);
public:
iterator &operator--();
iterator operator--(int);
iterator &operator++();
iterator operator++(int);
bool operator==(iterator const &other) const;
bool operator!=(iterator const &other) const;
int operator-(iterator const &rhs) const;
std::string &operator*() const;
bool operator<(iterator const &other) const;
iterator operator+(int step) const;
iterator operator-(int step) const;
iterator &operator+=(int step); // increment over `n' steps
iterator &operator-=(int step); // decrement over `n' steps
std::string *operator->() const;// access the fields of the
// struct an iterator points
// to. E.g., it->length()
};
typedef std::reverse_iterator<iterator> reverse_iterator;
class iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
iterator begin();
iterator end();
reverse_iterator rbegin();
reverse_iterator rend();
};
class StringPtr::iterator: public
std::iterator<std::random_access_iterator_tag, std::string>
{
friend class StringPtr;
friend bool operator==(iterator const &lhs, iterator const &rhs);
friend int operator-(iterator const &lhs, iterator const &rhs);
friend bool operator<(iterator const &lhs, iterator const &rhs);
friend iterator operator+(iterator const &lhs, int step);
friend iterator operator-(iterator const &lhs, int step);
std::vector<std::string *>::iterator d_current;
iterator(std::vector<std::string *>::iterator const &current);
public:
iterator &operator--();
iterator operator--(int);
iterator &operator++();
iterator operator++(int);
iterator &operator+=(int step); // increment over `n' steps
iterator &operator-=(int step); // decrement over `n' steps
std::string &operator*() const;
std::string *operator->() const;// access the fields of the
// struct an iterator points
// to. E.g., it->length()
};
//=
//PRIVATEIMP
@ -80,21 +84,24 @@ inline StringPtr::iterator StringPtr::iterator::operator++(int)
}
//=
//OPEQ
inline bool StringPtr::iterator::operator==(iterator const &other) const
inline bool operator==(StringPtr::iterator const &lhs,
StringPtr::iterator const &rhs)
{
return d_current == other.d_current;
return lhs.d_current == rhs.d_current;
}
//=
//OPNEQ
inline bool StringPtr::iterator::operator!=(iterator const &other) const
inline bool operator!=(StringPtr::iterator const &lhs,
StringPtr::iterator const &rhs)
{
return d_current != other.d_current;
return not (lhs == rhs);
}
//=
//OPSUB
inline int StringPtr::iterator::operator-(iterator const &rhs) const
inline int operator-(StringPtr::iterator const &lhs,
StringPtr::iterator const &rhs)
{
return d_current - rhs.d_current;
return lhs.d_current - rhs.d_current;
}
//=
//OP*
@ -104,21 +111,26 @@ inline std::string &StringPtr::iterator::operator*() const
}
//=
//CMP
inline bool StringPtr::iterator::operator<(iterator const &other) const
inline bool operator<(StringPtr::iterator const &lhs,
StringPtr::iterator const &rhs)
{
return d_current < other.d_current;
return lhs.d_current < rhs.d_current;
}
//=
//OPADD
inline StringPtr::iterator StringPtr::iterator::operator+(int step) const
inline StringPtr::iterator operator+(StringPtr::iterator const &lhs, int step)
{
return iterator(d_current + step);
StringPtr::iterator ret{ lhs };
ret.d_current += step; // avoids ambiguity
return ret;
}
//=
//OP-
inline StringPtr::iterator StringPtr::iterator::operator-(int step) const
inline StringPtr::iterator operator-(StringPtr::iterator const &lhs, int step)
{
return iterator(d_current - step);
StringPtr::iterator ret{ lhs };
ret.d_current -= step; // avoids ambiguity
return ret;
}
//=
//OPARITH

View file

@ -2,14 +2,16 @@ To grant nested classes access rights to the private members of other nested
classes, or to grant a surrounding class access to the private members of its
nested classes the hi(friend: nested classes)tt(friend) keyword must be used.
Note that no friend declaration is required to grant a nested class access to
the private members of its surrounding class. After all, a nested class is a
type defined by its surrounding class and as such objects of the nested class
are members of the outer class and thus can access all the outer class's
members. Here is an example showing this principle. The example won't compile
as members of the class tt(Extern) are denied access to tt(Outer)'s private
members, but tt(Outer::Inner)'s members em(can) access tt(Outer)'s private
members:
No friend declaration is required to grant a nested class access to the
private members of its surrounding class. Static members of the surrounding
class can directly be accessed, other members can be accessed if a surrounding
class object is defined by or passed to members of the nested class. After
all, a nested class is a type defined by its surrounding class and as such
objects of the nested class are members of the outer class and thus can access
all the outer class's members. Here is an example showing this principle. The
example won't compile as members of the class tt(Extern) are denied access to
tt(Outer)'s private members, but tt(Outer::Inner)'s members em(can) access
tt(Outer)'s private members:
verb(
class Outer
{

View file

@ -52,7 +52,42 @@ class definition:
return d_variable;
}
)
Here access to the members is defined as follows:
First note that in the Annotations(), in order to save space, nested class
interfaces are usually declared inside their surrounding class, as shown
above. For real-life projects this practice is questionable, as it clobbers
class interfaces, similarly to providing classes with in-class member
implementations. Instead of nesting class interfaces put them next to each
other:
verb(
class Surround
{
class SecondWithin;
public:
class FirstWithin;
};
class FirstWithin
{
int d_variable;
public:
FirstWithin();
int var() const;
};
class SecondWithin
{
int d_variable;
public:
SecondWithin();
int var() const;
};
)
For these three classes access to members is defined as follows:
itemization(
it() The class tt(FirstWithin) is visible outside and inside
tt(Surround). The class tt(FirstWithin) thus has global visibility.
@ -75,21 +110,24 @@ tt(SecondWithin) directly.
it() As always, an object of the class type is required before
its members can be called. This also holds true for nested classes.
)
To grant the surrounding class access rights to the private members
of its nested classes or to grant nested classes access rights to the
private members of the surrounding class, the classes can be defined as
tt(friend) classes (see section ref(NESTEDFRIENDS)).
To grant the surrounding class access rights to the private members of a
nested class the nested class may declare its surrounding class as a
friend. Conversely, as nested classes can be considered members of their
surrounding class their member functions have full access to the outer class
members, if they are provided with an outer class object (see section
ref(NESTEDFRIENDS)).
Nested classes can be considered members of the surrounding class, but
members of nested classes are em(not) members of the surrounding class. So, a
member of the class tt(Surround) may not access tt(FirstWithin::var)
directly. This is understandable considering that a tt(Surround) object is not
also a tt(FirstWithin) or tt(SecondWithin) object. In fact, nested classes are
just typenames. It is not implied that objects of such classes automatically
exist in the surrounding class. If a member of the surrounding class should
use a (non-static) member of a nested class then the surrounding class must
define a nested class object, which can thereupon be used by the members of
the surrounding class to use members of the nested class.
Although nested classes can be considered members of the surrounding
class, members of nested classes are em(not) members of the surrounding
class: members of the class tt(Surround) may not directly call
tt(FirstWithin::var). This is understandable considering that a
tt(Surround) object is not also a tt(FirstWithin) or tt(SecondWithin)
object. In fact, nested classes are just typenames. It is not implied that
objects of such classes automatically exist in the surrounding class. If a
member of the surrounding class should use a (non-static) member of a nested
class then the surrounding class must define a nested class object, which can
thereupon be used by the members of the surrounding class to use members of
the nested class.
For example, in the following class definition there is a surrounding
class tt(Outer) and a nested class tt(Inner). The class tt(Outer) contains a