我正在编写Java子集的编译器的后端。后端编写C ++代码。但是,有一些假设的Java代码,我不知道如何转换为C ++。
以下代码中显示了一个示例问题。 A由B扩展,B由C扩展,这里分别是三个头文件A.h,B.h和C.h:
#ifndef A_H
#define A_H
class B;
class A {
public: virtual B* get();
}
#endif /* !defined(A_H) */
==========================
#ifndef B_H
#define B_H
#include "A.h"
class C;
class B : public A {
public: virtual C* get();
}
#endif /* !defined(B_H) */
==========================
#ifndef C_H
#define C_H
#include "B.h"
class C : public B {
}
#endif /* !defined(C_H) */
可以看出,B覆盖A的方法get()。重写方法返回一个指向相应子类的指针,由于协方差,我猜这个子类在C ++中是有效的。
我不知道的是告知编译器的方式,C确实是B的子类,因此,重写方法是有效的。
B.h中C的前向声明,就像在代码中看到的那样,是不够的,因为它没有提到C的超类。
在B.h中包含C.h将是循环的,因为C.h已经包括B.h.后者是必需的,因为仅仅只有超类的前向声明是不够的。
可以做些什么?
编辑两条评论。
1其中一个海报声称,Java中不可能有以下内容,因此我添加了Java版本:
A.java:
class A {
public B get() {
return null;
}
}
B.java:
class B extends A {
public C get() {
return null;
}
}
C.java:
class C extends B {
}
它编译得很好。
2我并不坚持编译这些有些奇怪的案例。如果它们无法转换为C ++中的可读代码,那么很好,后端将失败并显示错误消息。事实上,我对解决C ++中的循环依赖关系的一般方法更感兴趣。
编辑2
谢谢大家,我对这个网站的效率印象深刻。
我的结论是,因为:
后端将:
干杯, 阿图尔
答案 0 :(得分:3)
当你用机器生成代码时,可以使用一些肮脏,肮脏的技巧。
class B;
class A {
public: virtual B* CLASS_A_get();
}
class C;
class B : public A {
public:
virtual B* CLASS_A_get();
virtual C* CLASS_B_get();
}
class C : public B {
}
// In B's .cpp file, you can include C.h
#include "C.h"
B* B::CLASS_A_get() {
return CLASS_B_get();
}
答案 1 :(得分:2)
您可以自己干净地实现协方差,而无需依赖编译器且无需任何强制转换。这是一个带有一些循环依赖的标题:
class A
{
public:
A* get() { return get_A(); }
private:
virtual A* get_A();
};
class B : public A
{
public:
C* get() { return get_C(); }
private:
virtual A* get_A();
virtual C* get_C();
};
class C : public A
{
public:
B* get() { return get_B(); }
private:
virtual A* get_A();
virtual B* get_B();
};
根据C :: get_B,用B :: get_C和C :: get_A实现B :: get_A。所有get_ *都在cxx文件中实现。您可以因为所有三个类已经完全定义。用户总是调用get()。
如果格式错误,我很抱歉,我是用手机发帖的。
编辑:使用静态强制转换的解决方案并不总是适用,例如当涉及虚拟继承时(那么你将需要动态强制转换)。
答案 2 :(得分:1)
我不确定你对问题起源的解释(编写编译器后端)是真实的,因为(1)所呈现的代码甚至不正确,缺少分号,我认为编写编译器的人会设法提供正确的代码,以及(2)Java代码中自然不会出现问题,我不确定它是否可以直接在Java中表达,除非我在下面显示的解决方法(在这种情况下你不需要)要问),(3)这不是一个难题,而不是编译器作家会遇到的问题。
也就是说,我强烈怀疑这是家庭作业。
那就是说,你只需要自己实现协方差,例如:像这样:
class B;
class A
{
private:
virtual B* virtualGet() { ... }
public:
B* get() { return virtualGet(); }
};
class C;
class B
: public A
{
private:
virtual B* virtualGet() { ... }
public:
C* get() { return static_cast<C*>( virtualGet() ); }
};
class C
: public B
{};
它与实现协变智能指针结果相同,只是对于智能指针结果,人们可以更多地依赖C ++对协变原始指针结果的支持。
这是一项众所周知的技术。
干杯&amp;第h。,
答案 3 :(得分:0)
严重的设计问题。
要使虚函数功能起作用,A,B和C类中的所有get()函数都应具有相同的签名。
将所有内容更改为:
虚拟A * get();
然后
A* ptr1 = new B;
ptr1->get(); // this will call the get function of class B.
A* ptr2 = new C;
ptr2->get(); // this will call the get function of class C.
这是你想要的吗?