C协方差/重写/循环问题
作者:互联网
我正在编写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
谢谢大家,我对这个网站的效率印象深刻.
我的结论是,因为:
>生成的头文件将被其他程序员使用;
>从您的答案中猜测,可能没有解决方案可以生成简单,可读的头文件;
>涉及回报类型的循环引用可能很少见;
>我避免使用C,因为除其他外,它允许这样的解决方案 –
我知道C有它的用途,但就个人而言,我更喜欢语法更简单的语言,比如Java;
后端将:
>尽可能使用前瞻性声明;
>否则将使用包括,检查后者是否为循环;如果是,它将失败并显示错误消息.
干杯,
阿图尔
解决方法:
您可以自己干净地实现协方差,而无需依赖编译器且无需任何强制转换.这是一个带有一些循环依赖的标题:
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().
对不起,如果格式错误,我用手机发帖.
编辑:使用静态强制转换的解决方案并不总是适用,例如当涉及虚拟继承时(那么你将需要动态强制转换).
标签:c,override,covariance,circular-dependency 来源: https://codeday.me/bug/20190826/1734870.html