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,10 +9,26 @@
class StringPtr: public std::vector<std::string *> class StringPtr: public std::vector<std::string *>
{ {
public: public:
class iterator: public 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> std::iterator<std::random_access_iterator_tag, std::string>
{ {
friend class StringPtr; 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; std::vector<std::string *>::iterator d_current;
iterator(std::vector<std::string *>::iterator const &current); iterator(std::vector<std::string *>::iterator const &current);
@ -22,26 +38,14 @@ class StringPtr: public std::vector<std::string *>
iterator operator--(int); iterator operator--(int);
iterator &operator++(); iterator &operator++();
iterator operator++(int); 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); // increment over `n' steps
iterator &operator-=(int step); // decrement over `n' steps iterator &operator-=(int step); // decrement over `n' steps
std::string &operator*() const;
std::string *operator->() const;// access the fields of the std::string *operator->() const;// access the fields of the
// struct an iterator points // struct an iterator points
// to. E.g., it->length() // to. E.g., it->length()
};
typedef std::reverse_iterator<iterator> reverse_iterator;
iterator begin();
iterator end();
reverse_iterator rbegin();
reverse_iterator rend();
}; };
//= //=
@ -80,21 +84,24 @@ inline StringPtr::iterator StringPtr::iterator::operator++(int)
} }
//= //=
//OPEQ //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 //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 //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* //OP*
@ -104,21 +111,26 @@ inline std::string &StringPtr::iterator::operator*() const
} }
//= //=
//CMP //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 //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- //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 //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 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. 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 No friend declaration is required to grant a nested class access to the
the private members of its surrounding class. After all, a nested class is a private members of its surrounding class. Static members of the surrounding
type defined by its surrounding class and as such objects of the nested class class can directly be accessed, other members can be accessed if a surrounding
are members of the outer class and thus can access all the outer class's class object is defined by or passed to members of the nested class. After
members. Here is an example showing this principle. The example won't compile all, a nested class is a type defined by its surrounding class and as such
as members of the class tt(Extern) are denied access to tt(Outer)'s private objects of the nested class are members of the outer class and thus can access
members, but tt(Outer::Inner)'s members em(can) access tt(Outer)'s private all the outer class's members. Here is an example showing this principle. The
members: 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( verb(
class Outer class Outer
{ {

View file

@ -52,7 +52,42 @@ class definition:
return d_variable; 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( itemization(
it() The class tt(FirstWithin) is visible outside and inside it() The class tt(FirstWithin) is visible outside and inside
tt(Surround). The class tt(FirstWithin) thus has global visibility. 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 it() As always, an object of the class type is required before
its members can be called. This also holds true for nested classes. its members can be called. This also holds true for nested classes.
) )
To grant the surrounding class access rights to the private members To grant the surrounding class access rights to the private members of a
of its nested classes or to grant nested classes access rights to the nested class the nested class may declare its surrounding class as a
private members of the surrounding class, the classes can be defined as friend. Conversely, as nested classes can be considered members of their
tt(friend) classes (see section ref(NESTEDFRIENDS)). 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 Although nested classes can be considered members of the surrounding
members of nested classes are em(not) members of the surrounding class. So, a class, members of nested classes are em(not) members of the surrounding
member of the class tt(Surround) may not access tt(FirstWithin::var) class: members of the class tt(Surround) may not directly call
directly. This is understandable considering that a tt(Surround) object is not tt(FirstWithin::var). This is understandable considering that a
also a tt(FirstWithin) or tt(SecondWithin) object. In fact, nested classes are tt(Surround) object is not also a tt(FirstWithin) or tt(SecondWithin)
just typenames. It is not implied that objects of such classes automatically object. In fact, nested classes are just typenames. It is not implied that
exist in the surrounding class. If a member of the surrounding class should objects of such classes automatically exist in the surrounding class. If a
use a (non-static) member of a nested class then the surrounding class must member of the surrounding class should use a (non-static) member of a nested
define a nested class object, which can thereupon be used by the members of class then the surrounding class must define a nested class object, which can
the surrounding class to use members of the nested class. 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 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 class tt(Outer) and a nested class tt(Inner). The class tt(Outer) contains a