调用派生类方法,当它被称为shared_ptr<Basic>

Call Derived class method when it's known as shared_ptr<Basic>

本文关键字:ptr gt lt Basic shared 类方法 派生 被称为 调用      更新时间:2023-10-16

我坚信这是一个非常常见的面向对象的问题,但是google并没有给我一个答案。我希望,有人能给我指出正确的方法来摆脱死锁。我尽量了解和使用标准技术,避免重复发明。

总结如下:

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. 设计是绝对错误的?

提前感谢。

问题是,当你使用/依赖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接口。总的教训是:没有数据成员的抽象接口是个好主意!

如果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();
}