C ++: Como posso evitar “tipo de retorno covariant inválida” em classes herdadas sem fundição?

StackOverflow https://stackoverflow.com/questions/2410532

  •  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)?

Foi útil?

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top