基于类实例的自动方法选择

时间:2017-07-24 13:36:13

标签: c++ oop downcast

我有两种相同方法的变体。我也有一个基类类型的实例,但我不知道它是一个实例的具体类。我现在想根据对象的实际类型自动选择合适的方法。这似乎是不可能的,我能想出的唯一解决方案是通过铸造检查所有可能性。 必须有一个更好的解决方案。

这是我的最小例子:

// Example program
#include <iostream>
#include <string>
#include <memory>

class A
{
public:    
    virtual void bar() const = 0;
};

class B : public A
{
public:
    void bar() const
    {
        std::cout << "B.bar()" << std::endl;
    }
};

class C : public A
{
public:    
    void bar() const
    {
        std::cout << "C.bar()" << std::endl;
    }    
};

class Z
{
public:
    Z(int variable) : m_variable(variable) {};

    void foo(std::shared_ptr<B> b)
    {
        std::cout << "Calling foo(B) method! " << m_variable << std::endl;
        b->bar();
    }

    void foo(std::shared_ptr<C> c)
    {
        std::cout << "Calling foo(C) method!" << m_variable << std::endl;
        c->bar();
    }
private:
  int m_variable;
};


int main()
{
  std::shared_ptr<A> b(new B());

  Z z(42);

  //z.foo(b); // This doesn't work

  // But this does
  std::shared_ptr<B> b_cast = std::dynamic_pointer_cast<B>(b);
  if (b_cast.get())
    z.foo(b_cast);
}

http://cpp.sh/9fqne

目前我不得不求助于dynamic_pointer_cast,但我发现它有点丑陋且不易维护。

我也不想将foo()的功能添加到类BC,因为这些是很小的独立数据结构,许多其他类在这些结构上运行。

非常感谢!

编辑:在原帖中我简化了一点。新的例子应该清楚了。

2 个答案:

答案 0 :(得分:1)

将纯虚函数foo()添加到基类中,并在后续派生类中重写。然后让您的全局函数foo()(与具有相同名称的成员函数无关)接受对std::shared_ptr const的引用作为参数:

#include <iostream>
#include <memory>
class A{
public:
    virtual void foo() = 0;
};

class B : public A{
public:
    void foo() override{
        std::cout << "Calling foo(B) method!" << std::endl;
    }
};

class C : public A{
public:
    void foo() override{
        std::cout << "Calling foo(C) method!" << std::endl;
    }
};

void foo(const std::shared_ptr<A>& param){
    param->foo();
}

int main(){
    std::shared_ptr<A> b = std::make_shared<B>();
    std::shared_ptr<A> c = std::make_shared<C>();
    foo(b);
    foo(c);
}

答案 1 :(得分:0)

As BoBTFish pointed outvisitor pattern是此问题的潜在解决方案:

// Example program
#include <iostream>
#include <string>
#include <memory>

class B;
class C;

class Visitor
{
public:
    virtual void visit(B* b) const = 0;
    virtual void visit(C* b) const = 0;
};

class A
{
public:    
    virtual void bar() const = 0;
    virtual void accept(const Visitor* visitor) = 0;
};

class B : public A
{
public:
    void bar() const
    {
        std::cout << "B.bar()" << std::endl;
    }

    void accept(const Visitor* visitor) 
    {
        visitor->visit(this);
    }
};

class C : public A
{
public:    
    void bar() const
    {
        std::cout << "C.bar()" << std::endl;
    }

    void accept(const Visitor* visitor) 
    {
        visitor->visit(this);
    }    
};

class Z : public Visitor
{
public:
    Z(int variable) : m_variable(variable) {};

    void visit(B* b) const
    {
        std::cout << "Calling foo(B) method! " << m_variable << std::endl;
        b->bar();
    }

    void visit(C* c) const
    {
        std::cout << "Calling foo(C) method!" << m_variable << std::endl;
        c->bar();
    }
private:
  int m_variable;
};


int main()
{
  std::shared_ptr<A> b(new B());

  Z z(42);

  b->accept(&z);
}

http://cpp.sh/2vah5

非常感谢!