Re: OOP design problem with dynamic_cast
Leslaw Bieniasz wrote:
Hello,
I have the following OOP design problem. I have a base class
designed as an element of a list, let's say:
class A
{
public:
// some stuff
A* Next;
A* Prev;
}
Don't forget the semicolon.
in which pointers Next and Prev serve for accessing next and
previous elements in the list. For simplicity, I declare here all
contents as public.
Class A is abstract. In practice, real lists are constructed using
various kinds of derived classes, for example:
Well, you didn't make A abstract, did you?
class B : public A
{
public:
// some stuff
B_Data *Data;
void foo(void);
}
(semicolon)
where B_Data is some data specific to class B, and method foo
serves for operations on Data. However, I need to be able to access
in foo not only the data in a given object, but also in other objects
in the list. Thus, I need to do something like this:
void B::foo(void)
{
B* bnext = dynamic_cast<B*>(Next);
B* bprev = dynamic_cast<B*>(Prev);
Data = bnext->Data + bprev->Data; // for example
// etc.
}
My question is: Is there any neat possibility for redesigning
the above construction, in order to avoid dynamic casting in foo?
Dynamic casting is quite expensive and regarded as not elegant.
On the other hand, I don't want to make Data available already in A,
because I have several different kinds of derived classes B, which differ
somewhat by the behaviour, and by the data they hold.
The above seems to be a common problem in situations when
some of the functionality is shared by the classes, so that making
a common base A is reasonable, but some other functionality is not shared.
I would offer two simple alternatives.
1) Use std::list from the standard library and get rid of A:
class B
{
public: void bar();
};
template <typename Itr>
void foo(Itr p)
{
Itr prev = p - 1;
Itr next = p + 1;
// play around *p, *prev and *next...
}
std::list<B> ls;
ls.push_back(B());
ls.push_back(B());
std::for_each(ls.begin(), ls.end(), std::mem_fun(B::bar));
2) Make class A a class template:
template <typename T>
class A
{
public: // note: not encapsulating...
T* prev;
T* next;
T val;
template <typename U>
A(T* p, T* n, const U& u):val(u){}
virtual ~A(){}
};
class B
{
public:
void bar();
};
void foo(A<B>& node)
{
B& curr = node.val;
B& prev = node.prev->val;
B& next = ndoe.next->val;
// play around curr, prev and next
}
IMHO you should be more cautious when using inheritance. Generally this
kind of data structuring doesn't not fit into the domain of OOP so B
should not inherit from A, never.
L. B.
Regards,
Ben