我有两个类,比如说Base和Derived:
class Base {
public:
virtual ~Base() = 0;
};
class Derived : public Base {};
还有一个函数foo:
auto foo (Derived* d) {
...
}
是否可以自动下调其参数?所以我可以做这样的事情:
Base* b = new Derived();
foo(b);
基本上,我想编写此函数而不在函数调用之前显式转换它。
我阅读了一些有关转换运算符/构造函数的信息,但在我看来它们没有用,您还有其他想法吗?
编辑:对不起,我用2个类和一个函数简化了这个问题。但是实际上我有一个包含50个函数的函数库和3个类(一个父类(super class)和2个子类)。不幸的是,这使最简单,最干净的解决方案不合适,因为在我看来(如果我错了,请纠正我),它们的伸缩性很差。
最佳答案
我可以根据您的需要考虑三种可能的解决方案。在示例中,我已经用unique_ptr
替换了原始指针。
情况1:您不需要每个派生类型的基本类型都相同。
使用CRTP允许基本类型将自身作为派生类型调用。示例实现:
template <typename DerivedType>
class Base {
template <typename F>
auto invoke_as_derived(F&& f) {
return std::forward<F>(f)(static_cast<DerivedType*>(this));
}
};
class Derived : public Base<DerivedType> {};
用法:
std::unique_ptr<Base<Derived>> b = std::make_unique<Derived>();
b->invoke_as_derived(foo);
由于您提到使用基本指针列表,因此这可能对您不起作用。
情况2:您需要共享的基本类型,但类型层次结构中只有一层,没有虚拟方法。
使用
std::variant
和 std::visit
。class Derived {};
using Base = std::variant<Derived, /* other derived types */>;
auto foo(Derived*) { ... }
class FooCaller {
operator ()(Derived& d) {
return foo(&d);
}
// Overload for each derived type.
}
用法:
Base b = Derived();
std::visit(FooCaller{}, b);
情况3:您需要一个基本类型,但还需要虚拟方法和/或类型层次结构中的其他层。
您可以尝试visitor pattern。它需要一些样板,但根据您的需要,它可能是最佳解决方案。执行示意图:
class Visitor; // Forward declare visitor.
class Base
{
public:
virtual void accept(Visitor& v) = 0;
};
class Derived : public Base
{
public:
void accept(Visitor& v) final { v.visit(*this); }
};
struct Visitor
{
virtual void visit(Derived&) = 0;
// One visit method per derived type...
};
struct FooCaller : public Visitor
{
// Store return value of call to foo in a class member.
decltype(foo(new Derived())) return_value;
virtual void visit(Derived& d)
{
return_value = foo(&d);
}
// Override other methods...
};
用法:
std::unique_ptr<Base> b = std::make_unique<Derived>();
FooCaller foo_caller;
b->accept(foo_caller);
您可以编写一个访问者,该访问者需要将一个函数应用于该元素,因此不必对所有许多函数都重复此操作。另外,如果您可以自己更改功能,则可以用访问者类型替换功能。
编辑:将调用语法简化回
foo(b)
为要传递
Base
对象的每个函数重载集定义一个重载。示例,使用第三种技术:auto foo(Base* b) {
FooCaller foo_caller;
b->accept(foo_caller);
return std::move(foo_caller.return_value);
}
现在
foo(b.get())
将在运行时委派给适当的foo
重载。关于c++ - 在C++中自动向下转换函数参数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51255820/