C++ 如何根据条件在不进行拼接的情况下向上投射此对象?

C++ 如何根据条件在不进行拼接的情况下向上投射此对象?,c++,c++17,C++,C++17,我遇到了一个可能很琐碎的问题。我想对AbstractParser的实例调用doSomething(),其中所述实例属于派生类FooParser或BarParser。它是一个还是另一个取决于用户提供的运行时参数。代码的其余部分应该只能访问父对象AbstractParser对象。见下文 AbstractParser& myParser; // Error: can't have a reference to nothing if(some_condition){ FooParse

我遇到了一个可能很琐碎的问题。我想对
AbstractParser
的实例调用
doSomething()
,其中所述实例属于派生类
FooParser
BarParser
。它是一个还是另一个取决于用户提供的运行时参数。代码的其余部分应该只能访问父对象
AbstractParser
对象。见下文

AbstractParser& myParser;   // Error: can't have a reference to nothing
if(some_condition){
    FooParser parser = FooParser();
    myParser = parser;
}else{
    BarParser parser = BarParser();
    myParser = parser;
}
// lots of code with other things ...
parser.doSomething();
根据一个条件,我想在
if
块的范围之外使用
myParser
(或指向它的指针),并且
myParser
应该作为适当的派生对象。我希望避免复制我的对象和(如果可能的话)移动构造函数。如果没有条件,我可以这样做

FooParser parser = FooParser();
AbstractParser &myParser = parser;     // upcast without slicing
// lots of code with other things ...
parser.doSomething();
它将是干净而优雅的,无需切片
解析器
即可向上投射。我不知道现在该怎么做


如何在不复制创建的对象或使其超出范围的情况下向上转换派生解析器?是否需要创建
std::unique_ptr
并在
if
中使用
make_unique()
?或者我应该使用一个返回对派生类的引用的函数吗?还是一个
静态\u cast
?还是我把它复杂化了?

您可以将解析器的用法抽象为一个函数,然后调用它。因此,来自:

AbstractParser&myParser;
if(条件()){
FooParser=FooParser();
stuff_1();
myParser=parser;
}否则{
BarParser=BarParser();
stuff_2();
myParser=parser;
}
stuff_3(myParser);
致:


使用完全独立的功能可能会更容易(例如,在这种情况下只需
stuff_3
,因此您不需要任何lambda),但lambda允许您捕获内容,因此不需要对其进行太多的重新设计。

简单的解决方案是使用
独特的\u ptr

std::unique_ptr<AbstractParser> myParser;
if (some_condition)
    myParser = std::make_unique<FooParser>();
else
    myParser = std::make_unique<BarParser>();

myParser->doSomething();

您可以执行以下操作:

std::variant解析器;
如果(某些条件){
parser=FooParser();
}否则{
parser=BarParser();
}
标准::访问([](自动和p){
如果constexpr(std::is_same_v){
}否则{
p、 doSomething();
} 
},解析器);

我认为这甚至可以省去函数调用的动态调度。

最简单的方法是将代码提取到单独的方法:

class-Foo{
void子操作(抽象解析器和解析器){
parser.doSomething();
}
无效操作(bool some_条件){
如果(某些条件){
福,福,;
子作用(foo);
}否则{
酒吧;
子作用(巴);
}
}
};

请注意,没有涉及堆。

这是典型的。您要求修复您的解决方案,但没有解释(提供足够的详细信息)此代码应该做什么。使用
std::unique\u ptr
可能是一个很好的解决方案,但可能有更好的方法来解决您的问题。@MarekR我认为我很清楚,但我已经重新编辑了。我想在
if
块内创建一个对象,并在
if
范围外保留一种访问其父接口的方法。我希望这是性能,因为在这个对象中复制是很重的问题的关键字是“指针”。你已经知道该做什么,只是没有意识到。使用指针代替引用,所显示的代码将大部分正常工作。将其设置为唯一的\u ptr,并使用
new
构建它。结束。如果您可以在编译时得到一些条件来计算,您可以使用条件模板来得到结果。@BlueMoon93您做了一些编辑,但看起来您没有抓住XY问题的关键。您当然可以使用
std::variant
,然后
std::visit
从中得到一个简单的引用,我们回到了原来的位置。更复杂,但是没有人指责C++是简单的,因为现在的代码< >分析器< /代码>被分配给堆?我将不得不研究什么是
std::variant
@BlueMoon93堆上的解析器似乎有什么问题?@tedlynmo在这种情况下,这不是问题。我想学习如何使用它,虽然,可能是有用的future@BlueMoon93好啊那么,您就有了上面显示的
变体
。我认为你会发现很少有情况下,花时间在堆栈上强制执行内容实际上是有意义的。我曾经处理过从堆栈中移动东西,以避免更频繁地出现堆栈溢出。你是对的。我添加了一个
std::monostate
默认类型。当然,这使得代码更加复杂。
std::unique_ptr<AbstractParser> myParser;
if (some_condition)
    myParser = std::make_unique<FooParser>();
else
    myParser = std::make_unique<BarParser>();

myParser->doSomething();
std::variant<std::monostate, FooParser, BarParser> var;
AbstractParser *myParser;
if (x)
    myParser = &var.emplace<FooParser>();
else
    myParser = &var.emplace<BarParser>();

myParser->doSomething();