[ 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
<include src="src/privatederiv/stack.h" href="src/privatederiv/stack.h" id="privderivstackh" mode="cpp"/>
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; }
<include src="src/privatederiv/stack-test.cpp" href="src/privatederiv/stack-test.cpp" id="stacktestcpp" mode="cpp"/>
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. |