我坚信这是一个非常常见的面向对象的问题,但谷歌的搜索并没有给我一个答案。我希望,有人可以指出我正确的方式如何摆脱我的僵局。我尝试了解并使用标准技术并避免重新发明轮子。
简而言之:
class A {
protected:
int _A;
public:
virtual void commonMethod() = 0;
void methodForMember_A();
}
class B : public A {
protected:
int _B;
public:
virtual void commonMethod()
void methodForMember_B();
}
class C : public B {
protected:
int _C;
public:
virtual void commonMethod()
void methodForMember_C();
}
class Basic {
protected:
// B or C instance
shared_ptr<A> _smth;
public:
Basic(shared_ptr<A> a_ptr) : _smth(a_ptr);
// calls A/B/C->commonMethod();
void commonMethod();
}
// Which works with B
class MoreSpecific : public Basic {
public:
MoreSpecific(shared_ptr<B> b_ptr) : Basic(b_ptr);
// calls b->methodForMemberB();
void specificMethod();
}
问题出在specificMethod()
,我希望致电_smth->methodForMemberB()
。
我可以看到以下方式:
投放所有specificMethods()
? (在我看来,铸件是一种救生艇,必须在非常复杂的情况下使用)
模板的时间? (不确定模板是否合适)
设计绝对错误?
提前谢谢。
答案 0 :(得分:2)
如果MoreSpecific
接口仅对B
个实例有效,则必须确保不将A
个对象设置为Basic::_smth
。您可以使用基类模板
template<typename T>
class BasicBase {
protected:
shared_ptr<T> _smth;
public:
BasicBase (shared_ptr<T> a_ptr) : _smth(a_ptr);
void commonMethod();
}
typedef BasicBase <A> Basic;
// Which works with B only
class MoreSpecific : public Basic<B> {
public:
MoreSpecific(shared_ptr<B> b_ptr) : Basic(b_ptr);
// calls b->methodForMemberB();
void specificMethod();
}
答案 1 :(得分:2)
问题在于,当您使用/依赖Basic
来存储B
指针时,您将丢失不仅仅是A
实例的信息。在这种情况下,您没有遵循(Liskov)继承原则!
有几种方法可以解决这个问题。模板是一种方式,但它取决于具体情况,在这种情况下,更“面向接口”的解决方案可能是合适的。在这种情况下的问题是您将B
存储在基类中,这就是我们在此避免的。相反,使用抽象接口:
class Basic {
protected:
virtual shared_ptr<A> getPtr () = 0;
public:
// calls A/B/C->commonMethod();, uses getPtr ()
void commonMethod();
};
// Which works with B
class MoreSpecific : public Basic {
protected:
// Store and implement interface for base classes
shared_ptr<B> b_ptr;
shared_ptr<A> getPtr () {return b_ptr;}
public:
MoreSpecific(shared_ptr<B> b_ptr) : b_ptr(b_ptr);
// calls b->methodForMemberB();
void specificMethod();
};
如果你真的需要一个存储裸A ptr的类,你可以让该类实现Basic
接口。要学习的一般教训是:没有数据成员的抽象接口是个好主意!