我最近想让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
a
、b
、c
和d
的类型都是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
类中提取正确的成员函数,那么这是不可行的。