不显式的向下转换



我有一个有两个子类的Basebar创建了一个类型为Baseunique_ptr,并尝试用它的一个子类初始化它。

当然,我不能在不显式指定类型的情况下进行向下转换,这是我不想做的。有什么方法可以绕过它吗?

struct Base
{
};
struct A : public Base
{
int val;
};
struct B : public Base
{
int val;
};
struct C : public Base
{
// does not have val
};
void bar(bool x, int value)
{
std::unique_ptr<Base> ptr;
if (x)
{
ptr = std::make_unique<A>();
}
else
{
ptr = std::make_unique<B>();
}
ptr->val = value;  // ERROR
}

c++中的类型不是这样工作的。

如果*ptr需要val,这必须反映在静态*ptr. type

在您的示例中,*ptr的静态类型是Base。这里没有val

数据流分析可以证明动态类型的*ptr总是有val,但这无关紧要。该实现不做数据流分析。它只查看静态类型。

如果你需要Base的一些后代有val而其他的没有,创建一个中间类BaseWithVal并使用它。

您可以使用通用的lambda或helper函数模板来避免代码重复:

void bar(bool x, int value)
{
auto make_ptr = [&]<typename T>(){
auto ptr = std::make_unique<T>();
ptr->val = value;
return ptr;
};
std::unique_ptr<Base> ptr;
if (x)
{
ptr = make_ptr.operator()<A>();
}
else
{
ptr = make_ptr.operator()<B>();
}
}

对于lambda上的显式模板形参,这需要c++ 20。在c++ 20之前,辅助函数更容易管理,尽管下面的替代方法也可以工作:

template<typename T>
struct type_identity {
using type = T;
};
void bar(bool x, int value)
{
auto make_ptr = [&](auto t){
using T = typename decltype(t)::type;
auto ptr = std::make_unique<T>();
ptr->val = value;
return ptr;
};
std::unique_ptr<Base> ptr;
if (x)
{
ptr = make_ptr(type_identity<A>{});
}
else
{
ptr = make_ptr(type_identity<B>{});
}
}

但是正如另一个答案所说,如果需要统一访问具有val成员的派生类子集,那么这些子类很可能与该成员共享一个中间基类。这样,您可以简单地将std::unique_ptr<Base>替换为std::unique_ptr<IntermediateBase>,一切都将正常工作。

相关内容

  • 没有找到相关文章

最新更新