我有两个类,比如说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个类(一个超类和2个子类)。不幸的是,这使最简单,最干净的解决方案不合适,因为在我看来(如果我错了,请纠正我),它们的伸缩性很差。
答案 0 :(得分:3)
我可以根据您的需要考虑三种可能的解决方案。在示例中,我用unique_ptr
替换了原始指针。
使用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);
由于您提到使用基本指针列表,所以这可能对您不起作用。
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);
您可以尝试使用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
适当的重载。
答案 1 :(得分:1)
通常的方法不是向下转换,而是使用虚函数。即将void foo()
放在课程的 中。
#include<iostream>
class Base {
public:
virtual ~Base() = default;
virtual void foo() { std::cout << "Base foo()\n"; }
};
class Derived : public Base {
public:
void foo() override { std::cout << "Derived foo()\n"; }
};
int main()
{
Base* b = new Derived();
b->foo();
delete b;
}
输出:
Derived foo()
如果您不想拨打Base::foo()
,可以设置
class Base {
public:
virtual ~Base() = default;
virtual void foo() = 0;
};
使Base
成为抽象类。
但是如果您真的要调用foo(b)
,则可以使用(模板化)帮助函数。例如:
#include<iostream>
class Base {
public:
virtual ~Base() = default;
virtual void foo() = 0;
};
class Derived : public Base {
public:
void foo() override {
std::cout << "Derived foo()\n";
}
};
template<typename T>
void foo(T* t)
{
t->foo();
}
int main()
{
Base* b = new Derived();
foo(b);
delete b;
}