方法参数中的C++动态绑定



我最近想让c++通过一些派生版本中的输入参数来动态解析成员/函数。我的意思是:

#include <iostream>
class Base {
};
class DerivedA : public Base {
};
class DerivedB : public Base {
};
class DerivedC : public Base {
};
class Test {
public:
    void world( DerivedA *instance )
    {
        std::cout << "DerivedA" << std::endl;
    }
    void world( DerivedB *instance )
    {
        std::cout << "DerivedB" << std::endl;
    }
    void world( Base *instance )
    {
        std::cout << "Base" << std::endl;
    }
};
int main()
{
    Base *a = new Base;
    Base *b = new DerivedA;
    Base *c = new DerivedB;
    Base *d = new DerivedC;
    Test hello;
    hello.world( a );
    hello.world( b );
    hello.world( c );
    hello.world( d );
    return 0;
}

我想要的行为是:

Base
DerivedA
DerivedB
Base

但可以肯定的是,我真正得到的输出是:

Base
Base
Base
Base

我知道,动态绑定是另一种方式,在基类的派生类中解析正确的成员函数,而不是像那样——但它能以任何方式工作吗?

也许我只是错过了要点。。

不过,提前表示感谢!

Sebastian

abcd的类型都是Base*。编译器不跟踪"变量包含的内容"。如果这就是你想要做的,那么你需要在你派生的类中使用一个虚拟函数,例如:

class Base {
 public: 
   virtual const char* MyName() { return "Base"; }
};
class DerivedA : public Base {
 public: 
   virtual const char* MyName() { return "DerivedA"; }
};
... similiar for all derived classes ... 
void world( Base *instance )
{
    std::cout << instance->MyName() << std::endl;
}

(编辑:要获得第一种情况中列出的行为,您需要不在DerivedC类中实现MyName()函数)

因此,使用包装类可能是测试设置的解决方案。这是我刚刚破解的东西,没有经过太多考虑和复杂:

#include <iostream>
class Base {
};
class DerivedA : public Base {
};
class DerivedB : public Base {
};
class DerivedC : public Base {
};
class Test {
public:
    void world( DerivedA *instance )
    {
        std::cout << "DerivedA" << std::endl;
    }
    void world( DerivedB *instance )
    {
        std::cout << "DerivedB" << std::endl;
    }
    void world( Base *instance )
    {
        std::cout << "Base" << std::endl;
    }
};
template<typename T>
class Wrapper
{
public:
    Wrapper(T* i) : instance(i)
    {
    }
    ~Wrapper()
    {
        delete instance;
    }
    void doTest(Test& t)
    {
        t.world(instance);
    }
    T* instance;
};

int main()
{
    Test hello;
    Wrapper<Base> a(new Base);
    Wrapper<DerivedA> b(new DerivedA);
    Wrapper<DerivedB> c(new DerivedB);
    Wrapper<DerivedC> d(new DerivedC);
    a.doTest(hello);
    b.doTest(hello);
    c.doTest(hello);
    d.doTest(hello);
    return 0;
}

在您的示例中,您没有运行时多态性方案(即动态绑定)。您所拥有的是一个重载成员函数,在重载解析中,编译器会正确地选择void world( Base *instance )

为了得到你想要的东西,你应该应用一个像下面这样的继承方案:

class Base {
public:
  virtual ~Base() {}
  virtual void world() const { std::cout << "Base" << std::endl; }
};
class DerivedA : public Base {
public:
  virtual ~DerivedA() {}
  void world() const { std::cout << "DerivedA" << std::endl; }
};
class DerivedB : public Base {
public:
  virtual ~DerivedB() {}
  void world() const  { std::cout << "DerivedB" << std::endl; }
};
class DerivedC : public Base {
public:
  virtual ~DerivedC() {}
  using Base::world;
};

实时演示

编辑:

为了将您的代码保持在一个地方,您可以在上面的方案中添加以下Test类的修改版本:

class Test {
public:
  void world( DerivedA *instance ) { instance->world(); }
  void world( DerivedB *instance ) { instance->world(); }
  void world( Base     *instance ) { instance->world(); }
};

实时演示

不幸的是,重载解析发生在编译时,而动态调度发生在运行时。因此,如果编译器打算从Base指针推导底层类型,然后从Test类中提取正确的成员函数,那么这是不可行的。

相关内容

  • 没有找到相关文章

最新更新