繁体   English   中英

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

[英]C++ Dynamic binding in method argument

我最近想让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

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

也许我只是想念要点。

但是,非常感谢!

塞巴斯蒂安

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类中选择正确的成员函数,那么这是不可行的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM