【问题标题】:How to superclass some data structs in C++?如何在 C++ 中对某些数据结构进行超类化?
【发布时间】:2012-07-09 01:56:06
【问题描述】:

我有一个包含 100 个数据结构的 C 头文件。我想创建一个每个数据结构都继承自的超类。怎么做?我应该解析头文件吗?反射?

因为每个 C 数据结构都是公共类,所以我可以创建一个超类,然后……然后呢?我不应该手动进入并显式地使每个结构都从超类继承?

【问题讨论】:

  • 你想解决什么真正的问题?
  • 我有一个包含大量 C 数据结构的 API。它们通过“send_transaction (datastruct_nr41)”发送到服务器,这是一个 C 函数调用。现在我想做一个 C++ 应用程序。每个数据结构消息都会有一些常用功能(序列化、反序列化等)。所以我想我从每个 C 数据结构中创建一个类,具有一个公共超类,具有公共功能。这更清楚了吗?
  • @Brutalizer:如果不知道调用的是哪个派生类型,基类如何序列化?或者你的意思是只添加接口并在派生类型中实现它?如果您打算仅在派生类型上实现它,为什么不创建一个并行层次结构来存储 C 结构(组合)并实现函数?
  • 我不懂并行层次结构。你有一些示例代码吗?我打算用工厂模式进行序列化。我从服务器得到一个二进制 blob,它是什么类型的数据结构?解决方案:gamedev.net/page/resources/_/technical/…
  • 等等,你希望结构体从一个类继承,并且仍然能够通过 C 函数 (send_transaction) 发送它们?

标签: c++ inheritance


【解决方案1】:

C/C++ 中没有反射,C++ 中也没有其他类的基类,所以这不是一件容易的事。您可以按照您的建议手动使您从超类继承的每个类,或者您可以创建一个基类,然后为每个数据结构创建一个新结构,该结构继承它的具体数据结构和基类。 例如http://liveworkspace.org/code/7e06e0374ef41bc4aeeafd55ae143527http://liveworkspace.org/code/7e06e0374ef41bc4aeeafd55ae143527
我认为手动使每个结构从 C 头文件中的基类继承会更有效。

【讨论】:

  • 嘿!这很好!谢谢!哇!我认为这对我来说很重要。有什么我可以学习的解决方案吗? :o) 谢谢!
  • 所以我需要为每个数据结构创建一个 XXX_Based 类,是吗?而且因为我有 100 个数据结构,我需要手动制作这些 XXX_Based 类吗?但这是一个很好的解决方案。我喜欢它。
  • 是的,这只是一个可行的解决方案,或者制作模板包装器,但是模板包装器将从您的结构继承,因此,包装器 将可以访问 S1 数据,但在您的代码你应该使用这个包装对象,而不是 S1 结构。
【解决方案2】:

我从未听说过使用继承的结构——这可能是某处的标准做法,但所有继承的例子都使用了类——将结构更改为类是否会造成困难?这可能会令人困惑,因为当我看到一个结构时,我倾向于认为是“C”。

您还确定通过继承,您仍然需要 100 个结构或类吗?如果它们确实没有重复数据,那没关系,但如果有重复字段,最好让它们相互继承以删除重复字段。

【讨论】:

  • API 使用不同的 C 数据结构,并且它有一些 C 函数可以将数据结构发送到后端。我的 C++ 应用程序将向后端服务器发送消息。这些消息是 C 数据结构。但是所有的 C 数据结构都会有一些共同的功能。我将如何处理? C头文件:结构A;结构 B;结构 C; ... send_datastruct (void *);您将如何在 C++ 中处理这种情况?创建一个通用的超类,每个 C 数据结构都继承自?有什么建议吗?
  • 您可以在 C++ 中覆盖基类函数,请参阅此 URL stackoverflow.com/questions/4869216/…
【解决方案3】:

对于您的特定用例,我将保留 C 代码原样,并利用 C 代码在 C++ 中创建您需要的任何解决方案。例如,您可以创建一个并行层次结构,其基础定义包括 serialize()deserialize() 的接口以及存储 C 结构之一并实现该特定类型的序列化的每个派生类型。

您也可以完全从外部解决这个问题,方法是提供为每个 C 结构定义的模板化 serialize/deserialize 函数...继承是 C++ 中最常被滥用的特性之一。

最佳解决方案将取决于您打算如何使用代码,但我会避免重写 C 代码(即编写编辑器以将 C 标头重写为 C++ 解决方案),因为这将有效地从 C 库中分支出来如果您需要在 C 端扩展它,您将需要维护两个单独的分支。

【讨论】:

  • 我不太明白你的意思。
  • struct BaseSerializable { virtual void serialize() = 0; }; struct XSerializer { C_type_X value; virtual void serialize() { ... }; }; 无需修改 C 类型,只需将类型的成员存储在 C++ 包装器中...但这也可能不是一个好的解决方案,这完全取决于其余的设计。
  • 我不明白如何使用此代码。 C_type_X 是数据结构吗?然后什么?如何将此代码与数据结构一起使用?
  • @Brutalizer:咳咳……您可以在外部使用您自己的类型层次结构来添加继承关系,而不是编辑 C 类型,您可以在其中使用现有的 C通过存储 C 结构并使用管理它们的现有代码来编写代码。您可能需要考虑深入研究一些推荐的编程书籍。
  • 哪些编程书籍涵盖了这一点?我是一名 Java 程序员并且读过 C++ 书籍——但我还不熟悉 C++。我知道我想做什么,但不知道如何在 C++ 中做到这一点。这就是我需要查看一些代码以便我理解的原因。元描述总是很容易理解,但是在 C++ 的实践中你是如何做到的呢?正如 Linus Torvalds 所说:“谈话很便宜,给我看代码!” ;o)
【解决方案4】:

如果你有一堆结构体:

显而易见的答案是巧妙地使用搜索和替换来使它们继承自新的基类。它无法访问结构的成员,但您可以将指向它们的指针全部存储在容器中

struct base {
    int dostuff() const {std::cout << "thing";}
};
struct thing1 : public base {
    int size;
};
//otherstructs inheriting from base
int main() {
    std::vector<std::unique_ptr<base>> objects;
    objects.push_back(std::unique_ptr<base>(new thing1()));
    objects[1].dostuff();
}

如果制作基类太难了,您可以尝试通过 wrapper 类添加函数。您将无法将指向它们的指针存储在容器中,但它们可以访问成员,只要结构具有相似的成员。

struct thing1 {
    int size;
};
//other unchanged structs
template<class mystruct>
struct wrapper : mystruct {
    int getsize() {return mystruct.size;}
};

int main() {
     wrapper<thing1> mything1;
     std::cout << mything1.size << mything1.getsize();
}

或者,如果您只是添加方法,请将它们设为单独的函数:

struct thing1 {
    int size;
};
//other unchanged structs
template<class T>
int getsize(const T& obj) {return obj.size;}

int main() {
     thing1 mything1;
     std::cout << mything1.size << getsize(mything1);
}

【讨论】:

  • 我喜欢您的解释,提供一些代码使其更清晰。谢谢。那么,我为每个数据结构创建一个包装器?在每个包装类内部,都有对数据结构本身的引用,还有一些函数?但那是代码重复,没有更简单的解决方案吗?特别是,我想使用这种模式。我从服务器得到一个二进制 blob,我需要找出它是哪个数据结构。这是一种解决方案:gamedev.net/page/resources/_/technical/…
  • 那么哪种方案更优雅呢?这个,还是 ForEveR 的那个?
  • ForEveR 建议您制作数百个新结构,我认为模板是一个更好的主意如果它们适合您的情况。模板想法不允许使用基本指针,而他的想法则允许使用。
  • 基指针,你的意思是,指向数据结构的指针?我真的不明白这段代码。我如何将它与 C 数据结构一起使用?你能提供更多的代码吗?但是,如果可以使用一个模板类而不是制作 100 个类,这会更整洁吗?您如何使您的代码看起来像带有一些标签的 C++ 代码?哪些标签?
  • @Brutalizer:我的意思是如果结构都继承自同一个基,那么您可以将指向这些结构的指针存储在单个容器中。我添加了很多代码来展示这三个想法。第一个需要 100 个新课程,第二个不需要。它们都有优点和缺点。
猜你喜欢
  • 2019-06-25
  • 2013-07-27
  • 2021-01-29
  • 1970-01-01
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多