[ fromfile: accessderivation.xml id: accessderivation ]
Most of the time, you are likely to see classes using public
derivation, for example
class Square : public Shape { // ... };
public
derivation describes an interface relationship between two classes.
This means that the interface (public
part) of the base class merges with the
interface of the derived class.
When it is correct to say that a derived object is a base
class object, public
derivation is appropriate.
For example, a Square is a Shape (with certain additional
attributes).
Much less commonly you might see protected
or private
derivation.
This is considered an implementation relationship, rather
than an is a relationship.
The base class interface (public
part) gets merged with the implementation (private
or protected
, depending on the kind of derivation)
of the derived class.
In effect, private
derivation is like adding an extra object as a private
data member to the derived class.
Similarly, protected
derivation is like adding an object as a protected
data member to the derived class, but it shares the this
pointer.
Example 22.10 is a concrete example of a situation in which
private
derivation might be appropriate.
The template class Stack
is privately derived from QList.
The rationale for doing this is that a stack is, by definition, a datastructure which limits access to the top
item.
The class QStack
,
which is publicly derived from QVector
,
has the expected public
interface for a stack but it also gives client code unlimited
access to the items in the stack because it contains the entire public
interface of
QVector
.
Our Stack
class is privately derived from QList so its public interface limits
client code access to the handful of stack operations that are consistent with the definition of that data
structure.
Example 22.10. src/privatederiv/stack.h
#ifndef _STACK_H_ #define _STACK_H_ #include <QList> template<class T> class Stack : private QList<T> { public: bool isEmpty() const { return QList<T>::isEmpty(); } T pop() { return takeFirst(); } void push(const T& value) { prepend(value); } const T& top() const { return first(); } int size() const { return QList<T>::size(); } void clear() { QList<T>::clear(); } }; #endif
Example 22.11 shows that an attempt by client code to
make use of the Stack
's base class (QList) interface is not allowed.
Example 22.11. src/privatederiv/stack-test.cpp
#include "stack.h" #include <QString> #include <qstd.h> using namespace qstd; int main() { Stack<QString> strs; strs.push("hic"); strs.push("haec"); strs.push("hoc"); // strs.removeAt(2); int n = strs.size(); cout << n << " items in stack" << endl; for (int i = 0; i < n; ++i) cout << strs.pop() << endl; }
Error, inherited QList methods are private. |
So, private
derivation provides a way to hide the public
interface of a
base class, for situations where the base class is needed only for implementation purposes.
What about protected
derivation?
Suppose you want to derive XStack
, a particular kind of stack, from this Stack
class.
With Stack
privately derived from QList, you will not be able to make use
of any QList member functions in the
implementation of XStack.
If you need to use some of the QList functions when you implement XStack
, then you must use protected
derivation when you
derive Stack
from QList.
protected
derivation makes the public
interface of QList protected
in Stack
.
Internally, this enables classes derived from Stack
to make use of the inherited
QList protected
interface.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |