c++ - 如何更改 C++ 对象的类(实现可变类型)

标签 c++ programming-languages interpreter variant

首先:我知道更改对象的类通常不是一个好主意,但我正在实现我自己的编程语言,它有可以包含任何类型值的变量,甚至可以更改它们的值随意输入,所以请假设我不是不了解 OO 基础知识的初学者。

目前,我在 C 中实现了变体变量。每个变体变量都有一个指向函数指针表的指针,其中包含 SetAsInt()SetAsString() 等函数., 然后是 C++ 中的实例变量。所有对象的大小都相同。

当一个变量包含一个字符串并且有人将一个 Int 分配给它时,我手动调用析构函数,将函数指针表更改为指向用于可变 int 值的表,然后然后设置它的 int 实例变量。

这有点难以维护,因为每次我添加一个新类型时,我都必须添加一个新的函数指针表并在其中填写所有函数指针。函数指针结构的类型检查似乎很糟糕,缺少字段不会导致投诉,所以我很容易不小心忘记列表中的一个指针并导致有趣的崩溃。此外,我必须重复所有在大多数类型中都相同的函数指针。

我想改为在 C++ 中实现我的可变参数类型,其中很多类型检查和继承默认行为都是由编译器为我完成的。有安全的方法吗?

PS - 我知道我可以创建一个包装器对象并使用 new 分配一个新对象,但我不能为每个 int< 增加额外的分配开销 堆栈上的变量。

PPS - 目前代码需要在 Linux、Mac、iOS 和 Windows 之间移植,但如果有人有标准的 C++ 解决方案,那就更好了。

PPPS - 类型列表是可扩展的,但在编译时预先确定。我的语言的基础层只定义了基本类型,但我的语言被编译成的主机应用程序添加了更多类型。

使用示例:

CppVariant someNum(42); // Creates it as CppVariantInt.

cout << "Original int: " << someNum->GetAsInt()
    << " (" << someNum->GetAsDouble() << ")" << endl;

someNum->SetAsInt(700); // This is just a setter call.

cout << "Changed int: " << someNum->GetAsInt()
    << " (" << someNum->GetAsDouble() << ")" << endl;

someNum->SetAsDouble(12.34); // This calls destructor on CppVariantInt and constructor on CppVariantDouble(12.34).

cout << "Converted to Double: " << someNum->GetAsInt()
    << " (" << someNum->GetAsDouble() << ")" << endl; // GetAsInt() on a CppVariantDouble() rounds, or whatever.

(想象一下,除了 double 和 int 之外,将来还会有其他类型,例如字符串或 bool 值,但是 GetAsInt()/SetAsInt() 的调用者不必知道它存储的是什么,只要因为它可以在运行时转换)

最佳答案

这是一个基于类型删除、 union 和模板特化的解决方案。
我不确定它是否符合您的要求。
无论如何,这是它得到的:

  • 任何东西都放在动态存储上
  • 不需要层次结构

您可以轻松地进一步改进它以减少代码量,但这旨在作为起点。

它遵循一个基于问题预期用途的最小工作示例:

#include<iostream>

class CppVariant {
    union var {
        var(): i{0} {}
        int i;
        double d;
    };

    using AsIntF = int(*)(var);
    using AsDoubleF = double(*)(var);

    template<typename From, typename To>
    static To protoAs(var);

public:
    CppVariant(int);
    CppVariant(double);

    int getAsInt();
    double getAsDouble();

    void setAsInt(int);
    void setAsDouble(double);

private:
    var data;
    AsIntF asInt;
    AsDoubleF asDouble;
 };

template<>
int CppVariant::protoAs<int, int>(var data) {
    return data.i;
}

template<>
int CppVariant::protoAs<double, int>(var data) {
    return int(data.d);
}

template<>
double CppVariant::protoAs<int, double>(var data) {
    return double(data.i);
}

template<>
double CppVariant::protoAs<double, double>(var data) {
    return data.d;
}

CppVariant::CppVariant(int i)
    : data{},
      asInt{&protoAs<int, int>},
      asDouble{&protoAs<int, double>}
{ data.i = i; }

CppVariant::CppVariant(double d)
    : data{},
      asInt{&protoAs<double, int>},
      asDouble{&protoAs<double, double>}
{ data.d = d; }

int CppVariant::getAsInt() { return asInt(data); }
double CppVariant::getAsDouble() { return asDouble(data); }

void CppVariant::setAsInt(int i) {
    data.i = i;
    asInt = &protoAs<int, int>;
    asDouble = &protoAs<int, double>;
}

void CppVariant::setAsDouble(double d) {
    data.d = d;
    asInt = &protoAs<double, int>;
    asDouble = &protoAs<double, double>;
}

int main() {
    CppVariant someNum(42);
    std::cout << "Original int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
    someNum.setAsInt(700);
    std::cout << "Changed int: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
    someNum.setAsDouble(12.34);
    std::cout << "Converted to Double: " << someNum.getAsInt() << " (" << someNum.getAsDouble() << ")" << std::endl;
}

关于c++ - 如何更改 C++ 对象的类(实现可变类型),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40572887/

相关文章:

c++ - GameMaker Studio,从 Windows DLL 创建异步事件

c++ - protected 数据成员的 protected 获取函数?

java - JVM/CLR 源代码兼容语言选项

programming-languages - 我怎样才能写出一个又快又脏的解释器?

Python CTRL+C 退出解释器?

python - 在 Python 中实现 lisp

c++ - 对象的静态成员 vector 的const_cast

c++ - 如何检索 SID 的字节数组

programming-languages - 不断变化的框架/API - 我们如何跟上?

c - 一些一般的 C 问题