У меня есть довольно сложная иерархия классов, в которой классы крестообразны друг в зависимости от друга: существует два абстрактных класса A и C, содержащий метод, который возвращает экземпляр C и A, соответственно. В их наследованных классах я хочу использовать ковариантный тип, который является в этом случае проблемой, так как я не знаю, что способ передать - объявляет отношения наследования.
Я получаю "тест cpp:22: ошибка: недопустимый ковариантный возврат вводит для ‘виртуального 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*, поскольку возврат вводит в наследованных классах (это было бы интуитивно мне, что существует путь)?
Я не знаю способа напрямую связать ковариантные члены в 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).
Насколько мне известно, это невозможно сделать без явного приведения типов. Проблема в том, что определение класса B
не может знать, что D
является подклассом C
, пока не увидит полное определение класса D
, но определение класса D
не может знать, что B
является подклассом A
, пока не увидит полное определение класса B
, и поэтому у вас есть круговая зависимость. Это не может быть решено с помощью форвардных объявлений, потому что форвардное объявление, к сожалению, не может определять отношения наследования.
Есть аналогичная проблема с попыткой реализовать ковариантный метод clone ()
с использованием шаблонов, , который, как я обнаружил, может быть решен , но аналогичное решение все еще не удается, потому что циклическая ссылка по-прежнему невозможно решить.
Вы не можете сделать это из-за ожиданий на стороне клиента. При использовании экземпляра C вы не можете сказать, какой это тип C (D или что-то еще). Таким образом, если вы сохраняете указатель B (полученный в результате вызова производного класса, но вы не знаете его во время компиляции) в указатель A, я не уверен, что вся память будет правильной.
Когда вы вызываете метод для полиморфного типа, среда выполнения должна проверять динамический тип объекта и перемещать указатели в соответствии с вашей иерархией классов. Я не уверен, что вам следует полагаться на ковариацию. Взгляните на это