C ++: Como posso evitar “tipo de retorno covariant inválida” em classes herdadas sem fundição?
-
18-09-2019 - |
Pergunta
I tem uma hierarquia de classe bastante complexo, no qual as classes são cruzada como dependendo um do outro: Existem duas classes sumário A e C contendo um método que retorna uma instância de C e A, respectivamente. Em suas classes herdadas eu quero usar um tipo de co-variante, que é neste caso um problema, já que eu não sei uma maneira de transmitir-declarar o navio relação herança.
Eu obter um "test.cpp: 22: erro: inválido tipo de retorno covariant para 'D virtual * B :: OUTC ()'" - erro, pois o compilador não sabe que D é uma subclasse de 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();
}
Se eu mudar o tipo de retorno de B :: OUTC () para C * de exemplo compila. Existe alguma maneira de manter B * e D * como tipos de retorno nas classes herdadas (que seria intuitivo para mim que há uma maneira)?
Solução
Não conheço nenhuma maneira de ter acoplada diretamente membros covariantes em C ++. Você vai ter tanto para adicionar uma camada, ou implementar retorno covariant si mesmo.
Para a primeira opção
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();
}
e para a segunda
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();
}
Note que esta segunda opção é o que é feito implicitamente pelo compilador (com algumas verificações estáticas que o static_cast é válido).
Outras dicas
Tanto quanto eu sei, não há nenhuma maneira de fazer isso sem conversão explícita. O problema é que a definição de B
classe não pode saber que D
é uma subclasse de C
até que ele vê uma definição completa da D
classe, mas a definição de D
classe não pode saber que B
é uma subclasse de A
até que ele vê uma definição completa de B
classe, e então você tem uma dependência circular. Isso não pode ser resolvido com a frente-declarações porque uma declaração para a frente, infelizmente, não é possível especificar um relacionamento de herança.
Há um problema semelhante com a tentativa de implementar um método clone()
covariant usando modelos, que eu encontrei pode ser resolvido , mas a solução análoga ainda falhar aqui, porque a referência circular permanece impossível de resolver.
Você não pode fazer isso devido ao cliente expectativa lado. Ao usar uma instância de C, você não pode dizer que tipo de C é (a D ou qualquer outra coisa). Assim, se você armazenar o ponteiro B (resultante de uma chamada para a classe derivada, mas você não sabe que em tempo de compilação) em um ponteiro A, eu não tenho certeza de que todo o material a memória vai estar certo.
Quando você chamar um método em um tipo polimórfico, o ambiente de execução tem de verificar o tipo dinâmico do objeto e ele se move ponteiros para atender à sua hierarquia de classes. Eu não tenho certeza que você deve confiar em covariância. Ter um olhar para este