Reputation: 154
Base class A:
class A {
public:
A() {}
~A() {}
void methodOfA() { fill(array_.begin(), array_.end(), 100); }
private:
vector<int> array_;
};
Decorator class B:
class B: public A {
A* a_;
public:
B(A* a) { a_ = a; }
~B() {}
A* getA() { return a_; }
};
Now if I create an instance of B and use it like the following:
A a;
B b(&a);
b.methodOfA();
I want b to access or change everything that a has. To do that, one can use:
b.getA()->methodOfA();
This does not look good to me, is there any way to do something like:
b.methodOfA();
but achieve the same effect as b.getA()->methodOfA(); Note that A may not have a copy constructor to copy everything to B and I want everything done to b that happen in a.
To clarify: If I override every member functions of A (e.g. methodOfA()) in B, I can achieve what I want above. But there are about 50 functions in A to override. Is there any better solution?
Upvotes: 0
Views: 833
Reputation: 63134
I see two solutions:
1 - Private inheritance
struct A {
void stuff() {}
};
struct B : private A {
using A::stuff;
};
int main() {
B b;
b.stuff(); // OK
}
You'll need to list all of A
's methods, but you don't have to redefine anything.
2 - Operator overloading
struct A {
void stuff() {}
};
struct B {
A *operator -> () {
return &a;
}
A a;
};
int main() {
B b;
b->stuff(); // Yuck. But OK.
}
On one hand, you can't have the b.stuff()
syntax without implementing the stuff
method in either B
or one of its bases. On the other hand, overloading an operator may not be intuitive to user code. I guess you'll have to choose your poison.
Upvotes: 1
Reputation: 62015
First of all, A::methodOfA()
needs to be virtual.
Then, in B, you need to add this:
virtual void methodOfA() { a_->methodOfA(); }
That's the decorator pattern.
Theoretically there could be a utility which, given a class, automatically generates a decorator for it, but I am not aware of any.
There is a number of things you can do to reduce the number of methods of A
so as to make writing your decorator easier:
Combine multiple methods which do not really need to be different into one. For example, raiseFlag()
and lowerFlag()
can become setFlag( bool flag )
.
Extract the public interface of A
into a separate class I
, and make both A
and B
extend I
. Then, remove utility methods of A
(methods implemented by invoking other methods of the same interface) put them in I
, and make them non-virtual. So, you will have a reference to an I
which implements some methods by itself, (invoking other methods on itself,) and this I
will be implemented by an instance of B
in which each virtual method delegates to (decorates) the corresponding virtual method of an instance of A
.
Also, please note that the problem with implementing the decorator pattern by writing one decorator method for each method in the original interface is just a fact of life and irrelevant to elegance. In engineering, elegance is about avoiding hacks, not about saving keystrokes.
Upvotes: 2