我正在尝试处理一个项目,该项目需要我在运行时确定多态对象的类型,以便我可以投射它。 我的意思的一个例子:
class A{
};
class B: public A{
public:
void foo(){
printf("B::foo()\n");
}
};
稍后,我会有一堆基本上存储的B对象:
std::vector<A*> v;
v.push_back(new B());
我需要调用某些定义为:
的重载方法void bar(B* b){
b->foo();
}
传入v
中存储的对象后。我遇到的问题是,在我的实际用例中,我在编译时不知道B
的类型,因此我不能只通过{{1}来调用bar
}}
我一直以为我可能需要的解决方案是以某种方式确定每个对象在运行时的类型,以便我可以在将其传递给bar((B*)v.get(0));
之前将其强制转换。
我到目前为止尝试的解决方案是使用bar
,但它对我不起作用,因为它只返回传入的值的静态类型,而不是运行时的类型。
另外,我不想在这个项目中使用第三方库,因为我希望它尽可能小。
感谢您的帮助。
编辑:
在我描述问题时,我认为我的意思并不清楚。在我的实际使用案例中(虽然我可以在必要时发布部分内容,但尝试在此处发布,但我试图编写一个库中有一个基类(在此表示为decltype
) )可以由用户扩展到他们自己的自定义类(此处表示为A
)。在我的示例中,B
只是表示B::foo()
的每个子类如何拥有自己的数据成员,稍后由某种方法处理(在我的示例中表示为A
)。这也是bar
不能简单地使用虚拟A
方法的原因。
我遇到的主要问题是,因为foo
应该是用户定义的,我不知道它在编译时是什么,但我在链接时做(因为链接来了后来)。这就是为什么使用B
(如Sam和Remy所建议的)不起作用的原因,因为根据我的理解,它要求我知道dynamic_cast
可能是什么的所有可能性,我不。虽然它看起来非常接近可能对我有用的东西。如果有某种方法可以获得所有可能的子类(例如,使用预处理器宏或模板),那么我认为这可能会起作用。
我希望这次我能更好地解释它。再次感谢您的帮助。
编辑2:另一个澄清点:在我正在处理的实际项目中,我只希望要求用户编写自己的B
类并重载B
以使用他们的自定义类。但是,我不希望要求用户拨打bar
。相反,我希望从基类(我定义)中调用bar
。这就是我尝试这样做的主要原因。那,并看看我能不能。
希望清除一切。再次感谢你。
答案 0 :(得分:4)
这就是虚拟方法的用途。
在foo()
中声明A
虚拟方法,你不必担心做丑陋的演员。
或者,如果A
至少有一个虚拟函数 - 而虚拟析构函数会执行 - 您可以试试dynamic_cast<>
的运气。
答案 1 :(得分:3)
在C ++中,(动态)polymorphism是此类事物的工具。
struct A {
virtual void foo() = 0;
virtual~A() {}
};
struct B : A {
void foo() override;
};
std::vector<std::unique_ptr<A>> vA;
vA.emplace_back(new B);
vA[0]->foo();
无需查找vA[0]
指向的对象的实际类型,virtual
函数调用机制将找到正确的函数(在本例中为B::foo()
)。请注意virtual
的{{1}}析构函数。它保证派生对象(class A
)从指向class B
的指针中正确删除(由A
保留)。
当然,还有unique_ptr<A>
,它允许您测试对象是否实际上是某种类型:
dynamic_cast<>
答案 2 :(得分:2)
我认为这对你有用。
首先,我们定义一个纯虚拟成员函数call_bar
,以便我们可以在基类A
上调用它。对于实现,我们需要正确的类型,但是CRTP用户类可以为我们指定它。
class A
{
public:
virtual void call_bar() = 0;
virtual ~A() {}
};
template <typename T>
class B : public A
{
public:
virtual void call_bar() override
{
bar(static_cast<T*>(this));
}
};
class C: public B<C>
{
};
答案 3 :(得分:0)
您正在寻找我一直以为我可能需要的解决方案是以某种方式确定每个对象在运行时的类型,以便我可以在将其传递给bar之前将其强制转换。
dynamic_cast
:
class A
{
public:
virtual ~A() {}
};
class B: public A
{
public:
void foo() {
printf("B::foo()\n");
}
};
...
std::vector<A*> v;
v.push_back(new B);
...
A *a = v.get(0);
B *b = dynamic_cast<B*>(a);
if (b)
bar(b);