gpt4 book ai didi

没有虚函数的 C++ 动态调度

转载 作者:IT老高 更新时间:2023-10-28 23:16:44 25 4
gpt4 key购买 nike

我有一些遗留代码,而不是虚拟函数,使用 kind 字段进行动态调度。它看起来像这样:

// Base struct shared by all subtypes
// Plain-old data; can't use virtual functions
struct POD
{
int kind;

int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();
};

enum Kind { Kind_Derived1, Kind_Derived2, Kind_Derived3 /* , ... */ };

struct Derived1: POD
{
Derived1(): kind(Kind_Derived1) {}

int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();

// ... plus other type-specific data and function members ...
};

struct Derived2: POD
{
Derived2(): kind(Kind_Derived2) {}

int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();

// ... plus other type-specific data and function members ...
};

struct Derived3: POD
{
Derived3(): kind(Kind_Derived3) {}

int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();

// ... plus other type-specific data and function members ...
};

// ... and so on for other derived classes ...

然后POD类的函数成员是这样实现的:

int POD::GetFoo()
{
// Call kind-specific function
switch (kind)
{
case Kind_Derived1:
{
Derived1 *pDerived1 = static_cast<Derived1*>(this);
return pDerived1->GetFoo();
}
case Kind_Derived2:
{
Derived2 *pDerived2 = static_cast<Derived2*>(this);
return pDerived2->GetFoo();
}
case Kind_Derived3:
{
Derived3 *pDerived3 = static_cast<Derived3*>(this);
return pDerived3->GetFoo();
}

// ... and so on for other derived classes ...

default:
throw UnknownKindException(kind, "GetFoo");
}
}

POD::GetBar()POD::GetBaz()POD::GetXyzzy()等成员实现类似的。

这个例子被简化了。实际代码有大约十几种不同的 POD 子类型和几十种方法。 POD 的新子类型和新方法的添加非常频繁,因此每次我们这样做时,我们都必须更新所有这些 switch 语句。

处理这种情况的典型方法是在 POD 类中声明函数成员 virtual,但我们不能这样做,因为对象驻留在共享内存中.有很多代码依赖于这些结构是普通的旧数据,所以即使我能找到某种方法在共享内存对象中拥有虚函数,我也不想这样做。

因此,我正在寻找有关清理此问题的最佳方法的建议,以便所有关于如何调用子类型方法的知识都集中在一个地方,而不是分散在几十个 switch 几十个函数中的语句。

我想到的是,我可以创建某种适配器类来包装 POD 并使用模板来最小化冗余。但在我开始走这条路之前,我想知道其他人是如何处理这个问题的。

最佳答案

您可以使用跳转表。这是大多数虚拟调度在底层的样子,您可以手动构建它。

template<typename T> int get_derived_foo(POD*ptr) {
return static_cast<T>(ptr)->GetFoo();
}
int (*)(POD*) funcs[] = {
get_derived_foo<Derived1>,
get_derived_foo<Derived2>,
get_derived_foo<Derived3>
};
int POD::GetFoo() {
return funcs[kind](this);
}

举个简短的例子。

共享内存的具体限制是什么?我意识到我在这里不够了解。这是否意味着我不能使用指针,因为另一个进程中的某个人会尝试使用这些指针?

您可以使用字符串映射,其中每个进程都有自己的映射拷贝。您必须将其传递给 GetFoo() 以便它可以找到它。

struct POD {
int GetFoo(std::map<int, std::function<int()>& ref) {
return ref[kind]();
}
};

编辑:当然,你不必在这里使用字符串,你可以使用 int。我只是用它作为例子。我应该把它改回来。事实上,这个解决方案非常灵活,但重要的是,复制特定于流程的数据,例如函数指针之类的,然后传入。

关于没有虚函数的 C++ 动态调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4693229/

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