gpt4 book ai didi

c++ - unique_ptrs 的循环 vector 并为运行时类型调用正确的重载

转载 作者:行者123 更新时间:2023-11-28 02:14:08 25 4
gpt4 key购买 nike

我有一个 vectorunique_ptr 到共享一个公共(public)基类的对象。我想遍历 vector 并根据存储的类型调用函数的正确重载。问题是这个函数不是该类的成员(对于那些喜欢谈论设计模式的人:假设我正在实现一个访问者类并且 fVisit 方法)。考虑以下代码示例(或 try it online ):

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class Base{ public: virtual ~Base() {}; };
class A : public Base { public: virtual ~A() {} };
class B : public Base { public: virtual ~B() {} };
class C : public Base { public: virtual ~C() {} };

void f(Base* b) { cout << "Calling Base :(\n"; }
void f(A* a) { cout << "It is an A!\n"; }
void f(B* b) { cout << "It is a B\n"; }
void f(C* c) { cout << "It is a C!\n"; }

template<class Derived>
void push(vector<unique_ptr<Base>>& v, Derived* obj)
{
v.push_back(std::unique_ptr<Derived>{obj});
}

int main() {
vector<unique_ptr<Base>> v{};
push(v, new A{});
push(v, new B{});
push(v, new C{});

for(auto& obj : v)
{
f(obj.get());
}

return 0;
}

我的代码有一些表面上的差异(f 是一个类方法而不是一个自由函数,我不使用 using namespace std)但是这显示了一般主意。我明白了

Calling Base :(
Calling Base :(
Calling Base :(

而我希望看到

It is an A!
It is a B!
It is a C!

我想知道是否可以调用正确的 f 重载(我想完全摆脱 f(Base*) 版本).

一种选择是按照以下方式进行手动类型检查

     if(dynamic_cast<A>(obj) != nullptr) f((A*)obj);
else if(dynamic_cast<B>(obj) != nullptr) f((B*)obj);
...

但这实在是太丑了。另一种选择是将 f 移动到 Base,但如前所述,我正在实现访问者模式,并且更愿意将 Visit 方法保留在我正在访问的对象树。

谢谢!

编辑: 显然我的代码示例给人的印象是我的类型必须是非虚拟的——实际上我对添加虚拟方法没有根本的反对意见,所以我将其添加到代码示例。

最佳答案

为了能够在运行时选择正确的函数,您需要一些虚函数(除非您想在对象中自己编写一些类型信息函数并增加一些调度开销)。

最简单的方法是使 f() 成为基类的虚拟成员函数,并为每个派生类型提供覆盖版本。但是你已经取消了这种方法。

另一种可能的解决方案是使用像这样的虚拟调度函数来使用类似双重调度的技术:

class Base { 
public:
virtual void callf() { f(this); }
virtual ~Base() {}
}
class A : public Base {
public:
void callf() override { f(this) }; // repeat in all derivates !
}
class B : public Base {
public:
void callf() override { f(this) }; // repeat in all derivates !
}
...
void F(Base *o) { // this is the function to be called in your loop
o->f();
}

诀窍是编译器会在每个callf() 函数中找到正确的f() 函数,使用this 的真实类型>.
F() 函数将调用虚拟调度函数,确保它是与执行时对象的真实类型相对应的函数。

关于c++ - unique_ptrs 的循环 vector 并为运行时类型调用正确的重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34566909/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com