1

我坚信这是一个非常常见的面向对象问题,但很难谷歌搜索并没有给我答案。我希望有人能指出我摆脱僵局的正确方法。我尝试了解和使用标准技术,避免重新发明轮子。

简而言之:

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()

我可以看到以下方式:

  1. 全部铸造specificMethods()?(在我看来,铸造是一种救生艇,必须在非常复杂的情况下使用)

  2. 模板的时间?(不确定模板是否适合此处)

  3. 设计是绝对错误的?

先感谢您。

4

2 回答 2

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();
}
于 2013-05-27T13:29:46.530 回答
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接口。要学习的一般教训是:没有数据成员的抽象接口是个好主意!

于 2013-05-27T13:31:29.617 回答