13

我有一个非常复杂的类层次结构,其中类相互依赖:有两个抽象类 A 和 C,其中包含一个分别返回 C 和 A 实例的方法。在他们继承的类中,我想使用协变类型,在这种情况下这是一个问题,因为我不知道一种方法来前向声明继承关系。

我得到一个“test.cpp:22: error: invalid covariant return type for 'virtual D* B::outC()'” - 错误,因为编译器不知道 D 是 C 的子类。

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

如果我将 B::outC() 的返回类型更改为 C*,则示例编译。有什么方法可以将 B* 和 D* 作为继承类中的返回类型(对我来说有一种方法很直观)?

4

3 回答 3

8

我不知道在 C++ 中有直接耦合的协变成员。您必须要么添加一个层,要么自己实现协变返回。

对于第一个选项

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class BI : public A {
public:
};

class D : public C {
public:
        BI* outA();
};

class B: public BI {
public:
        D* outC();
};

D* B::outC() {
        return new D();
}

BI* D::outA() {
        return new B();
}

第二个

class C;

class A {
public:
        C* outC() { return do_outC(); }
        virtual C* do_outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
        virtual C* do_outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return static_cast<D*>(do_outC());
}

C* B::do_outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

请注意,第二个选项是由编译器隐式完成的(通过一些静态检查来确定 static_cast 是否有效)。

于 2010-03-09T16:38:23.383 回答
4

据我所知,如果没有明确的强制转换,就没有办法做到这一点。问题是 class 的定义在看到 class 的完整定义之前B不能知道这D是一个子类,但是 class 的定义在看到 class 的完整定义之前不能知道这是一个子类,并且所以你有一个循环依赖。这不能通过前向声明来解决,因为不幸的是前向声明不能指定继承关系。CDDBAB

尝试clone()使用模板实现协变方法也有类似的问题,我发现可以解决,但是类似的解决方案在这里仍然失败,因为循环引用仍然无法解决。

于 2010-03-09T16:45:37.367 回答
0

由于客户端的期望,您不能这样做。使用 C 实例时,您无法分辨它是哪种 C(D 或其他)。因此,如果您将 B 指针(来自对派生类的调用但您在编译时不知道)存储到 A 指针中,我不确定所有内存内容是否正确。

当您在多态类型上调用方法时,运行时环境必须检查对象的动态类型并移动指针以适应您的类层次结构。我不确定你应该依赖协方差。看看这个

于 2010-03-09T16:31:52.837 回答