gpt4 book ai didi

c++ - 用新类型覆盖基类成员

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:47:11 30 4
gpt4 key购买 nike

我正在尝试使用 C++ 来模拟动态类型之类的东西。我正在处理继承类的问题。例如,一个函数可以定义为

BaseClass* myFunction(int what) {
if (what == 1) {
return new DerivedClass1();
} else if (what == 2) {
return new DerivedClass2();
}
}

基类和每个派生类都有相同的成员,但类型不同。例如,BaseClass 可能有 int xyz = 0(表示什么都没有),DerivedClass1 可能有 double xyz = 123.456 ,并且 DerivedClass2 可能有 bool xyz = true。然后,我可以创建返回一种类型但实际上返回几种不同类型的函数。问题是,当我尝试这样做时,我总是访问 xyz 的基类版本。我试过使用指针(void* 用于基类,“正确”指针用于派生类),但每次我想访问该成员时,我都必须执行类似 *(double*)(obj->xyz) 最终变得非常困惑和不可读。

这是我的代码大纲:

#include <iostream>

using std::cout;
using std::endl;

class Foo {
public:
Foo() {};

void* member;
};

class Bar : public Foo {

public:
Bar() {
member = new double(123.456); // Make member a double
};

};

int main(int argc, char* args[]) {
Foo* obj = new Bar;

cout << *(double*)(obj->member);

return 0;
};

我想我想问的是,这是“好的”编码实践吗?如果不是,对于返回多种类型或接受多种类型的函数是否有不同的方法?

最佳答案

这实际上不是这样做的方法。

有两种典型的方法可以在 C++ 中实现类似于动态类型的东西:

  • 面向对象的方式:类层次结构和Visitor 模式
  • 函数式编程方式:标记 union

后者使用 boost::variant 相当简单,前者在网络上有详细记录。我个人建议从 boost::variant 开始。

如果您想走完整的动态类型之路,那么事情就会变得更加棘手。在动态类型中,一个对象通常表示为包含其他对象和函数的字典,函数接受对象的列表/字典并返回对象的列表/字典。用 C++ 建模是可行的,但会很罗嗦......


How is an object represented in a dynamically typed language ?

更通用的表示是语言将对象表示为一组值(通常命名)和一组方法(也命名)。简化表示如下:

struct Object {
using ObjectPtr = std::shared_ptr<Object>;
using ObjectList = std::vector<ObjectPtr>;
using Method = std::function<ObjectList(ObjectList const&)>;

std::map<std::string, ObjectPtr> values;
std::map<std::string, Method> methods;
};

如果我们以 Python 为例,我们意识到我们遗漏了几件事:

  1. 例如,我们无法实现 getattr,因为 ObjectPtrMethod 的类型不同
  2. 这是一个递归实现,但没有基础:我们缺少固有类型(通常是BoolIntegerString , ...)

处理第一个问题相对容易,我们将我们的对象转换为能够成为可调用:

class Object {
public:
using ObjectPtr = std::shared_ptr<Object>;
using ObjectList = std::vector<ObjectPtr>;
using Method = std::function<ObjectList(ObjectList const&)>;

virtual ~Object() {}

//
// Attributes
//
virtual bool hasattr(std::string const& name) {
throw std::runtime_error("hasattr not implemented");
}

virtual ObjectPtr getattr(std::string const&) {
throw std::runtime_error("gettattr not implemented");
}

virtual void setattr(std::string const&, ObjectPtr) {
throw std::runtime_error("settattr not implemented");
}

//
// Callable
//
virtual ObjectList call(ObjectList const&) {
throw std::runtime_error("call not implemented");
}

virtual void setcall(Method) {
throw std::runtime_error("setcall not implemented");
}
}; // class Object

class GenericObject: public Object {
public:
//
// Attributes
//
virtual bool hasattr(std::string const& name) override {
return values.count(name) > 0;
}

virtual ObjectPtr getattr(std::string const& name) override {
auto const it = values.find(name);
if (it == values.end) {
throw std::runtime_error("Unknown attribute");
}

return it->second;
}

virtual void setattr(std::string const& name, ObjectPtr object) override {
values[name] = std::move(object);
}

//
// Callable
//
virtual ObjectList call(ObjectList const& arguments) override {
if (not method) { throw std::runtime_error("call not implemented"); }
return method(arguments);
}

virtual void setcall(Method m) {
method = std::move(m);
}
private:
std::map<std::string, ObjectPtr> values;
Method method;
}; // class GenericObject

处理第二个问题需要递归:

class BoolObject final: public Object {
public:
static BoolObject const True = BoolObject{true};
static BoolObject const False = BoolObject{false};

bool value;
}; // class BoolObject

class IntegerObject final: public Object {
public:
int value;
}; // class IntegerObject

class StringObject final: public Object {
public:
std::string value;
}; // class StringObject

现在您需要添加功能,例如值比较。

关于c++ - 用新类型覆盖基类成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20583987/

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