当前位置: 首页 > 知识库问答 >
问题:

我如何在C语言中为一个包装类实现多态性,这个包装类将保存几种类型中的一种?

徐博雅
2023-03-14

我是一个有成就的C程序员,我用C编写了汇编程序和虚拟机(https://github.com/chucktilbury/assembler(大部分工作,但不完整))我正在考虑将它移植到C,这样我就可以使用STL了。这是一个爱好项目,没有期望对任何人都有用。

我的VM有一个Value的概念,它可以有几种类型中的一种。我使用一个嵌入联合的结构来实现它。这导致了一堆巨大的宏来执行简单的事情,例如加法和比较。

我想做的是有一个基类,可以用来引用一个值和实现特定类型的子类,这样我就不必详细说明如何检索值实现的数据。

换句话说,这就是我所拥有的:

    ...
    switch(left_val->type) {
        ...
        case FLOAT:
            switch(right_val->type) {
            ...
                case INTEGER:
                    result->type = FLOAT;
                    result->data.float_val = left_val->data.float_val + right_val->data.int_val;
                    break;
            ...
            }
        ...
    }

我想看到的是:

  result->add(left_val, right_val); // over-simplified, I know....

显然,我可以像在C中那样做,这是我的下意识反应。但是我觉得我忽略了C语言中的一些要点。

据我所知,没有办法实现我想要的,因为C(像C一样)是一种静态类型的语言。我不妨将丑陋的东西封装在一个类中,然后像我目前在C中所做的那样传递Value(s)。

这种说法是否普遍同意?还是我完全错了?

共有2个答案

干永丰
2023-03-14

我用C写了一些非常相似的东西,我假设你对性能没有期望。以下是一些可能有帮助的要点:

您将需要一种方法来存储每条数据的类型信息。您应该使用类来实现此目的,而不是将数据类型存储在枚举中。如果您希望能够支持嵌入额外的类型,您的类型系统应该是健壮的。因为我的目标是面向对象的语言,所以我包含了类型的数据成员和成员函数(包括操作符和构造函数)。

如果您只想使用内置类型,您可以注册对象/类来处理每种类型的运算符。因此,一旦您获得了一段数据,您就可以获取其类型并调用必要的函数。您可以使用多态来执行此系统,但每次复制数据时,您也会复制该类型。因此,您需要有一个可以正确克隆您的对象的函数。您也可以选择更简单的路线,但这会占用更多内存。

Type IntType() {
    Type t;
    t.addition = &add<int>;
    //...
    return t;
}

您还可以只创建一个IntType,然后为每个数据分配它的指针。类似于vftable的东西。

为了实际存储数据,我使用了我的Any结构,它非常类似于std::any(我是在2014年左右写的)。您可以对数据存储使用std::any。你必须小心那些不能被复制的类型。

如果您想自己查看该项目,可以在此处公开获得。你应该得到 4.x-dev 分支。系统处于“源/脚本”中。祝你好运。

姬安志
2023-03-14

我建议使用< code>std::variant和< code>std::visit来减少样板文件

例:

#include <cstdint>
#include <variant>

using INTEGER = std::intmax_t;
using FLOAT = long double;

using Value = std::variant<INTEGER, FLOAT>;

auto operator+(const Value& lhs, const Value& rhs) {
    return std::visit([](auto&& l, auto&& r) -> Value { return l + r; }, lhs, rhs);
}

现在,添加两个 INTEGERs 将生成一个包含 INTEGER 的变体。在添加中包含 FLOAT 将使结果成为 FLOAT,就像在语言的正常规则中一样。

示例用法:

int main() {
    Value i = 10;
    Value f = 3.14159;

    auto r = i + f;
}

演示

C 20 版本(由 user17732522 提供):

auto operator+(const Value& lhs, const Value& rhs) {
    return std::visit<Value>(std::plus{}, lhs, rhs);
}
 类似资料:
  • 问题内容: 我想将特定类的每个方法包装在python中,并且希望通过最少地编辑该类的代码来实现。我应该怎么做? 问题答案: Michael Foord的Voidspace博客的一个条目中介绍了一种优雅的实现方法,该条目在“方法修饰元类的方法”部分中介绍了什么是元类以及如何使用它们。稍微简化一下,然后将其应用于您的情况会导致以下结果: 在Python中,函数/方法装饰器只是函数包装器和一些语法糖,以

  • 我有以下xml类型: FaxNumber类型如下所示: 生成的xml应该如下所示: 运行JAXB XJC从XSD生成java类时,它会生成以下类: 但是,我想绑定FaxNumber到这样的复合类: 有没有办法在JAXB绑定xml中定义这样的绑定? 注意:不幸的是,我无法控制并且无法更改XSD

  • 我是否遗漏了包装类中的某些细节? 我有以下程序,在其中我定义了一个类,它包装并提供运算符: 我以为这会编译成同样的东西--它在做同样的计算,所有的东西都是内联的。 编辑-如果我使用而不是,它将产生相同的输出。 编辑-我发布了错误的ASM版本(而不是),因此本节没有帮助。 我在我的Mac电脑上使用Xcode的gcc,在一个64位系统上。除了for-loop的主体之外,结果是相同的。

  • 我的困惑从这里开始,假设我们在HDFS中有一些数据需要使用下面运行在hadoop代码中的Java代码来处理 在这段代码中,Hadoop的类型类似于LongWritable,Text,intwritable。 让我们选择包裹在Java字符串类型周围的Text类型(如果是错误的请纠正我)。 我的疑问是,当我们在上面的代码中将这些参数传递给我们的方法映射时,这些参数如何与)交互 下面是文本类代码 我的第

  • CGO是C语言和Go语言之间的桥梁,原则上无法直接支持C++的类。CGO不支持C++语法的根本原因是C++至今为止还没有一个二进制接口规范(ABI)。一个C++类的构造函数在编译为目标文件时如何生成链接符号名称、方法在不同平台甚至是C++的不同版本之间都是不一样的。但是C++是兼容C语言,所以我们可以通过增加一组C语言函数接口作为C++类和CGO之间的桥梁,这样就可以间接地实现C++和Go之间的互

  • 两者的计算结果都为false。(顺便说一句,比较是不必要的,因为类不会重写Object中的equals。) 和都是,因为它们可比,没有错误。比较两个具有不同声明的泛型类型的对象是非法的。 在进一步检查时,字段将通过调用包私有的本机方法,如下所示: 除了Java文档对“表示基元类型”的模糊暗示之外,我找不到任何关于这方面的文档。这个领域有什么用处吗?它在包装类本身中没有使用。 (编辑) 是真的。 还