I got these virtual classes from a library that implement an algorithm in the form of abstract classes
class A{
public :
virtual void foo() = 0 ;
};
class B{
public:
void setA(A * a) { m_a = a ;}
virtual void f() = 0;
void g() {m_a->foo();}
protected:
A开发者_如何学编程 * m_a ;
};
To use the library you just have to derive the classes and implement the pure virtual functions, like foo()
, and provide other methods specific to the implementation as well (bar()
).
class dA : public A {
public :
void foo() {/* ... */}
void bar() {/* ... */}
};
class dB : public B {
public :
void f() ;
};
I would typically use these class by calling
dB * mydB = new dB() ;
mydB->setA(new dA() );
mydB->f() ;
mydB->g() ;
But I have a design problem when implementing dB::f()
, because I need to call dA::bar()
which is specific to dB
. But in the class, I only keep a reference to dB trough a B*. Then I have thought of two options :
- use a
dynamic_cast
each timef()
is called to castB::m_a
into adB*
- add a m_dA member to dB which stores the same pointer as m_a, but can be used to access dB specific functions.
Of course I can't change the the base classes.
I would like to know if there is a more elegant solution to this problem (like a design pattern I did not thought of). If not, which one should I choose ?
You've a third solution. Add a function setA()
in the dB
. Of course, this function will hide B::setA()
which is good for you if dB::setA()
is implemeted as:
class dB : public B
{
dA *m_dA ; //add this member also!
public :
void f()
{
m_dA->bar(); //fast forward : no cast here!
}
void setA(A *a) //this hides B::setA()
{
m_dA= dynamic_cast<dA*>(a); //just one time dynamic cast!
if ( m_dA == 0 )
{
throw std::runtime_error("invalid argument");
}
B::setA(a); //now call the hidden function in the base!
}
};
In this way, you don't need to dynamic_cast each time you call dB::f()
, which makes the call fast!
dB
as a concrete class should not call methods on dA
an unrelated concrete class. Even with reinterpret_cast
this is bad design which couples the unrelated objects uneccessarily. The common functionality should be put in a common base class or interface.
For example class A
can be considered an interface as it has nothing but pure virtual methods. Therefore it would be safe to use multiple inheritance if you wanted that interface on dB
as well. You of course would then have to implement your own foo
in that case.
class dB : public B, public A {
public :
void f();
void foo();
};
If bar()
is the one you want and for some reason you can change the interface A
then make your own interface which provides a pure virtual function bar()
and then make both dA
and dB
inherit from your new interface and implement bar()
accordingly and use interface pointers to that.
If you must use one in terms of the other then composition is the way to go but not of the ambiguous base pointer which may fail a dynamic cast. Make a concrete dA
member within dB
perhaps.
Your dB can only work if the A it has is actually a dA. You need to make sure that this is always the case.
Hence over-ride the setA method to use a dynamic_cast to check that it really is a dA. Now whether you then at that point save the result in m_dA or dynamic cast again later is unimportant. There's less possibility of having an incorrectly initialised dB, whose dynamic cast may fail later.
精彩评论