从基类的唯一指针中声明派生类的类型

Decltype of derived class from unique pointer to base class

本文关键字:派生 声明 类型 指针 基类 唯一      更新时间:2023-10-16

我想进行运行时多态性,并且必须知道实际类型,例如计算某个派生类的实例。以下是我目前所拥有的:

标题

struct Base {
virtual ~Base();
};
struct DerivedFoo : public Base {};
struct DerivedBar : public Base {};

Base::~Base() {}
int main() {
std::vector<std::unique_ptr<Base>> my_array{};
my_array.emplace_back(std::make_unique<DerivedFoo>());
my_array.emplace_back(std::make_unique<DerivedBar>());
for (const auto& elem : my_array) {
if (std::is_same<DerivedFoo, decltype(elem)>::value) {
// do something
}
// some testing
std::cout << typeid(decltype(elem)).name() << 'n';
std::cout << typeid(decltype(*elem)).name() << 'n';
std::cout << typeid(decltype(*elem.get())).name() << 'n';
}
return 0;
}

输出

St10unique_ptrI4BaseSt14default_deleteIS0_EE
4Base
4Base
St10unique_ptrI4BaseSt14default_deleteIS0_EE
4Base
4Base

问题是:我只设法得到基类的类型。不是派生的。所以我从不输入if语句。

  • 我可以添加一个虚拟函数"GetID(("或类似的函数。但我觉得这是多余的。我应该能够用类型特征来做到这一点
  • 我查看了std::unique_pointer<...>::element_typestd::pointer_traits,但无法使其运行

有什么想法吗?

代码中的问题是期望运行时多态性,但只使用编译时类型:

  • decltype(x)提供了x的编译时类型
  • 所以typeid(decltype(x))是指编译时类型的运行时类型信息,所以在您的示例中是4Base

如果要使用运行时类型,请直接在对象上使用typeid,如下所示:

std::cout <<< typeid(elem).name() << 'n';
std::cout << typeid(*elem).name() << 'n';
std::cout << typeid(*elem.get()).name() << 'n';

结果看起来像:

St10unique_ptrI4BaseSt14default_deleteIS0_EE
10DerivedFoo
10DerivedFoo
St10unique_ptrI4BaseSt14default_deleteIS0_EE
10DerivedBar
10DerivedBar

同样,std::is_same<DerivedFoo, decltype(elem)>::value是基于模板类型推导的,所以再次编译。如果您想在运行时对多态类型进行检查,则需要使用以下构造:

if (dynamic_cast<DerivedFoo*>(&*elem)) {
// do something
}

使用访问者模式

struct Counter;
struct Foo;
struct Bar;
struct BarBar;
struct Counter {
int barCount = 0;
int barBarCount = 0;
void visit(Bar *bar) {
barCount += 1;
}
void visit(BarBar *bar) {
barBarCount += 1;
}
};
struct Foo {
virtual void accept(Counter* v) = 0;
};
struct Bar : public Foo {
void accept(Counter* v) override {
v->visit(this);
}
};
struct BarBar : public Foo {
void accept(Counter* v) override {
v->visit(this);
}
};

int main()
{
std::vector<std::unique_ptr<Foo>> foos;
foos.emplace_back(std::make_unique<Bar>());
foos.emplace_back(std::make_unique<BarBar>());
Counter counter;
for(const auto& foo : foos) {
foo->accept(&counter);
}
std::cout << counter.barCount << " " << counter.barBarCount << std::endl;
}

输出1 1