Esse código é legal?
class Base1 {
};
class Base2 {
public:
virtual ~Base2() {
if (!dynamic_cast<Base1*>(this))
std::cout << "aaaa" << std::endl;
}
Base2() {
}
};
class MyClass: public Base1, public Base2 {
public:
MyClass() {
}
virtual ~MyClass() {
std::cout << "bbb" << std::endl;
}
};
int main() {
MyClass s;
return 0;
}
Vejo as duas impressões, mas devo ver apenas uma. Eu acho que o elenco dinâmico está errado. É possível fazer uma verificação desse tipo?
c++
polymorphism
destructor
multiple-inheritance
dynamic-cast
greywolf82
fonte
fonte
!
dynamic_cast
comporta de maneira diferente em construtores e destruidores?Respostas:
Talvez eu tenha encontrado a solução, a resposta é não, não é possível:
Do ponto 6 da documentação do cppreference.com :
Veja também [class.cdtor] / 6 da norma.
Desde que estou transmitindo para Base1 no destruidor Base2, esse comportamento é indefinido.
fonte
[class.cdtor]/6
, para referência. Desculpe, não 5. Era 5 em C ++ 17 (rascunho N4659), parece que é/6
agora.this
é do tipo do destruidor, então não vejo esse UB sendo aplicado. O mesmo parágrafo padrão diz, no entanto, que o tipo mais derivado do objeto sob destruição será considerado a classe do destruidor, de modo que o comportamento explicado na outra resposta seja observado.Concordo com a resposta do @ j6t, mas aqui está um raciocínio expandido com referências padrão.
O comportamento especial de
dynamic_cast
objetos em construção e destruição é descrito por [class.cdtor] / 5 do padrão C ++ 17 (rascunho final) e equivalentemente pelas versões padrão anteriores.Em particular, diz:
O comportamento indefinido não se aplica aqui, pois o operando é a expressão
this
, que trivialmente tem o tipo de um ponteiro para a própria classe do destruidor, uma vez que aparece no próprio destruidor.No entanto, a primeira frase afirma que o
dynamic_cast
comportamento se comportará como se*this
fosse um objeto do tipo mais derivadoBase2
e, portanto, o elenco aBase1
que nunca será bem-sucedido, porqueBase2
não é derivado deBase1
, edynamic_cast<Base1*>(this)
sempre retornará um ponteiro nulo, resultando no comportamento que você está vendo.cppreference.com afirma que o comportamento indefinido ocorre se o tipo de destino da conversão não for o tipo da classe do destruidor ou uma de suas bases, em vez de aplicar isso ao tipo de operandos. Eu acho que isso é apenas um erro. Provavelmente, a menção de " novo tipo " no ponto 6 da bala deveria dizer " expressão ", o que faria corresponder à minha interpretação acima.
fonte
O
dynamic_cast
está bem definido nessa situação. É correto que você observe as duas linhas de saída.Você está errado ao supor que no destruidor de
Base2
this
é uma classe derivada. No momento, a parte da classe derivada já foi destruída, portanto, não pode mais ser uma classe derivada. De fato, no momento em que o destruidor deBase2
execuções, o objeto apontado porthis
é apenas umBase2
objeto. ComoBase2
não está relacionado deBase1
forma alguma, odynamic_cast
retorna um ponteiro nulo e o condicional é inserido de acordo.Edit: O padrão diz :
O operando
this
refere-se ao objeto que está sendo destruído. Portanto, a classe do destructor (Base2
) é considerada a classe mais derivada, e esse é o motivo pelo qual o objeto não está relacionado ao tipo de destino (Base1*
) de nenhuma maneira. Além disso, o tipo estático do operandothis
éBase2* const
, o que claramente é um ponteiro para a própria classe do destruidor. Portanto, a regra sobre comportamento indefinido não se aplica. Em resumo, temos um comportamento bem definido.fonte
[class.cdtor]/6
mencionei nas outras respostas o mesmo que cppref: "Se o operando do dynamic_cast se referir ao objeto em construção ou destruição e o tipo estático do operando não for um ponteiro ou objeto do construtor ou própria classe do destruidor ou uma de suas bases, o dynamic_cast resulta em um comportamento indefinido ".