编辑:全面检修
我正在制作一种编程语言(类似于 Python),至少现在,我正在尝试将它编译成 C++
。我遇到一个错误,其中 C++
表示类 “Object”
中没有成员 “value”
。这是一个编译错误。我理解 为什么 C++
这样做,因为它必须在编译时知道 value
的类型,所以我要求 < em>备选方案。
它唯一会给出的是 Object 的实例子类,其中成员 "value"
将被定义,这是一个编译错误。
我不能在 Object
类中声明成员 "value"
,因为它的类型取决于它所在的子类。这也必须与 floats 和字符串,因此使用 Integer 实例而不是 Object 实例定义函数将不起作用。
下面是一些代码,其中包含如何使用这些对象的示例:
auto user_i = std::make_unique<Integer>(2);
std::cout << (*user_i).equals(*std::make_unique<Float>(2.0).get()) << std::endl;
这里是重要的类定义:
class Object {
public:
bool equals(Object& other) {
throw "Not implemented!";
}
};
class Integer: public Object {
public:
int value;
Integer(int val) {
value = val;
}
bool equals(Object& other) {
return value == other.value;
}
};
class Float: public Object {
public:
double value;
Float(double val) {
value = val;
}
bool equals(Object& other) {
return value == other.value;
}
};
class String: public Object {
public:
string value;
String(string val) {
value = val;
}
bool equals(Object& other) {
return value.compare(other.value) == 0;
}
};
不应该是2 == "2"
,而是应该是2 == 2.0 == 2.000
等
然后是像 add
这样的方法的复杂化(我的意思是返回一个值,仍然不修改对象)。 @Michael Karcher 建议的 equals
方法可以正常工作,但是例如 2+3
应该返回 5
,而不是 5.00000
.
更麻烦的是,用户定义的 Object
(在我的语言中是 Class
)应该能够覆盖 add
等方法。
最佳答案
除了主要问题之外,您的示例还有几个问题。我从小问题着手解决它们。
- 您需要声明
equals
作为virtual
在基类中。 与 Java 不同,动态分派(dispatch)不是 C++ 中的默认设置,但必须使用virtual
按方法请求像这样的属性:
class Object {
public:
virtual bool equals(Object other) {
throw "Not implemented";
}
}
- 您要按值 传递要与之比较的对象。 与 Java 不同,在 C++ 中甚至可以按值传递类类型。这意味着函数
equals
获取Object
的拷贝与 - 比较,只是。您要比较的对象部分,包括value
成员,不要复制到传递给equals
的参数中.您应该通过引用 传递参数。作为您的equals
函数不需要修改您比较的对象,一个没有写权限的引用(由于语法原因通常称为 const 引用)就足够了:
class Object {
public:
virtual bool equals(const Object& other) {
throw "Not implemented";
}
}
- 如果您编写的基类仅提供需要在每个派生类中重写的函数签名,则您不会让它抛出任何东西,而是通过将其声明为纯来使其抽象virtual 函数,使用
=0
句法。这可以防止您意外创建Object
无法比较的实例。这将捕获丢失的传递引用:
class Object {
public:
virtual bool equals(const Object& other) = 0;
}
现在,让我们来回答您的问题:
这种方法适用于 JavaScript 或 Python 等动态类型语言,但不适用于 C++。 在编译过程中,编译器必须知道在哪里可以找到成员 value
在对象中 other
及其类型。如果你只是传入任何 Object
,编译器无法知道它。甚至 你 也不知道:类型可能是 int
或 float
.所以你和编译器都不知道你传递给比较的对象中是float值还是int值。如果Integer
对象应该与 Integer
都具有可比性和 Float
对象,您要么需要比较方法,要么需要一种方法来获得通用 value
一种常见的类型。在这种情况下,在具有 32 位整数的机器上,每个整数值都可以在 double
中精确表示变量。您可以向 Object
添加第二个函数类名为 as_double
像这样:
class Object {
public:
virtual bool equals(const Object &other) const = 0;
virtual double as_double() const = 0;
}
我还标记了方法const
,这意味着您可以在对象上调用它们或使用您可能不会写入的引用。现在你可以实现 Integer
和 Float
像这样:
class Integer: public Object {
public:
int value;
Integer(int val) {
value = val;
}
bool equals(const Object & other) const {
return value == other.as_double();
}
double as_double() const {
return value;
}
};
class Float: public Object {
public:
double value;
Float(double val) {
value = val;
}
bool equals(const Object & other) const {
return value == other.as_double();
}
double as_double() const {
return value;
}
};
而且,如果您查看 equals
方法,现在这两种类型几乎相同:您将参数的值提取为 double 值,并将其与本地值进行比较(在 Integer
的情况下,本地值也被隐式转换为 double 值。所以您可以还使用在两个对象上调用 to_double
的通用比较实现,您不必费心在每个子类中实现 equals
:
class Object {
public:
bool equals(const Object& other) const {
return as_double() == other.as_double();
}
virtual double as_double() const = 0;
}
请注意,这仅适用于 double
实际上能够表示所有值——甚至那些存储在 Integers
中的值.如果您的实际用例没有可以转换为的通用类型,则您需要更复杂的解决方案。
关于C++14类函数错误: "Object has no attribute ' value'",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56762243/