Conversão de tipos de classes avançada - C ++

Started by ÐλяkFeλя, 05 de July , 2008, 12:35:38 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ÐλяkFeλя

CONVERSÃO DE TIPOS DE CLASSES AVANÇADAS
Até agora, para converter o tipo de um objeto simples em outro, usamos o operador de conversão de tipos tradicional. Por exemplo, para converter um número real do tipo double para um inteiro do tipo int nós usamos:

Quoteint i;
double d;
i = (int) d;

ou também

Quotei = int (d);

Isso é muito bom para tipos básicos que têm conversões definidas padrão, porém esses operadores também podem se aplicados indiscriminadamente em classes e ponteiros para classes. Então, é perfeitamente válido escrever coisas como:

Quote// conversão de tipo de classe

#include

 

class CDummy {

    int i;

};

 

class CAddition {

        int x,y;

  public:

        CAddition (int a, int b) { x=a; y=b; }

        int result() { return x+y;}

};

 

int main () {

  CDummy d;

  CAddition * padd;

  padd = (CAddition*) &d;

  cout << padd->result();

  return 0;

}

Embora o programa anterior seja correto sintaticamente em C++ (na verdade irá compilar sem avisos na maioria dos compiladores), seu código não faz muito sentido, pois usamos a função result que é um membro de CAddition sem ter declarado um objeto dessa classe: padd não é um objeto, é somente um ponteio no qual atribuímos o endereço de um objeto não relacionado. Ao acessar seu membro result, irá produzir um erro de execução ou, no mínimo, somente um resultado inesperado.

Para que se possa controlar esses tipos de conversões entre classes, o padrão ANSI-C++ definiu quatro novos operadores de conversão: reinterpret_cast, static_cast, dynamic_cast e const_cast. Todos eles possuem o mesmo formato ao serem usados:

Quotereinterpret_cast (expressão)

    dynamic_cast (expressão)

     static_cast (expressão)

      const_cast (expressão)


No qual novo_tipo é o tipo de destino no qual expressão precisa ser convertido. Para fazer um paralelismo simples de ser entendido com os operadores tradicionais de conversão de tipos, essas expressões significam:

(novo_tipo) expressão
novo_tipo (expressão)

mas com suas próprias características especiais.

reinterpret_cast

reinterpret_cast converte um ponteiro para outro tipo de ponteiro. Também permite converter de um ponteiro para um tipo inteiro e vice e versa.

Esse operador pode converter ponteiros entre classes não-relacionadas. A operação resulta em uma simples cópia binária do valor de um ponteiro para outro. O conteúdo apontado não passa por qualquer checagem nem transformação entre tipos.

No caso da cópia ser feita de um ponteiro para um inteiro, a interpretação de seu conteúdo depende do sistema e, sendo assim, qualquer implementação não é portável. Um ponteiro convertido para um inteiro grande o suficiente para contê-lo por completo pode ser convertido de volta para um ponteiro válido.

Quoteclass A {};
class B {};
A * a = new A;
B * b = reinterpret_cast(a);

reinterpret_cast trata todos os ponteiros exatamente como os operadores de conversão de tipos tradicionais os tratam.
static_cast

static_cast faz qualquer conversão que possa ser feita implicitamente assim como a conversão inversa (mesmo se não for permitido implicitamente).

Aplicado em ponteiros para classes, ou seja, que permite converter um ponteiro de uma classe derivada para a classe base (essa é uma conversão válida que pode ser feita implicitamente) e também pode fazer o inverso: converter uma classe base para seu tipo derivado.

No último caso, a classe base que está sendo convertida não é checada para determinar se essa é uma classe completa do tipo de destino ou não.

Quoteclass Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * b = static_cast(a);

static_cast, além de manipular ponteiros para classes, também pode ser usado para fazer conversões definidas explicitamente em classes, assim como fazer conversões padrão entre tipos fundamentais:

Quotedouble d=3.14159265;
int i = static_cast(d);

dynamic_cast

dynamic_cast é usado exclusivamente com ponteiros e referências a objetos. Permite qualquer conversão de tipos que possa ser feita implicitamente assim como a conversão inversa usada com classes polimórficas, porém, diferentemente da checagem de static_cast, dynamic_cast, nesse último caso, se a operação for válida. Ou seja, checa se a conversão irá retornar um objeto completo válido do tipo requisitado.

A checagem é feita durante a execução. Se o ponteiro que estiver sendo convertido não for um objeto completo válido do tipo requisitado, o valor retornado é um ponteiro NULO.

Quoteclass Base { virtual dummy(){}; };
class Derived : public Base { };
 
Base* b1 = new Derived;
Base* b2 = new Base;
Derived* d1 = dynamic_cast(b1);   // funciona
Derived* d2 = dynamic_cast(b2);   // falha: retorna NULO

Se a conversão de tipos for feita para um tipo referência e essa conversão não for possível, uma exceção do tipo bad_cast será gerada:

Quoteclass Base { virtual dummy(){}; };
class Derived : public Base { };
 
Base* b1 = new Derived;
Base* b2 = new Base;
Derived d1 = dynamic_cast(b1);   // funciona
Derived d2 = dynamic_cast(b2);   // falha: exceção gerada

const_cast

Esse tipo de conversão manipula o atributo const do objeto passado, seja para ser acionado ou removido:

Quoteclass C {};
const C * a = new C;
C * b = const_cast (a);

Nenhum dos outros três novos operadores de cast pode modificar a constância de um objeto.

typeid

ANSI-C++ também define um novo operador chamado typeid que permite a checagem do tipo de uma expressão:

typeid (expressão)

esse operador retorna uma referência a um objeto constante do tipo type_info que é definido no arquivo de cabeçalho padrão . Esse valor retornado pode ser comparado com outro usando os operadores == e != ou pode servir para obter uma string de caracteres que representa o tipo de dados ou o nome da classe usando seu método name().

Quote// typeid, typeinfo

#include

#include

 

class CDummy { };

 

int main () {

  CDummy* a,b;

  if (typeid(a) != typeid(b))

  {

    cout << "a e b sao de tipos diferentes:\n";

    cout << "a e: " << typeid(a).name() << '\n';

    cout << "b e: " << typeid(b).name() << '\n';

  }

  return 0;

}

a e b sao de tipos diferentes:
a e: class CDummy *
b e: class CDummy