C++
Home

Fazendo coerção de ponteiros da classe base para ponteiros da classe derivada

Um objeto de uma classe derivada publicamente também pode ser tratado como um objeto de sua classe base correspondente.

Isso possibilita coisas interessantes.

Por exemplo>
Podemos ter duas classes derivadas de uma classe base com metodos diferentes, porém isso não impede uma lista encadeada deles, desde que tratemos os objetos derivados como objetos da classe base.

Nos podemos usar uma coerção explícita para converter um ponteiro de uma classe base para um ponteiro de uma classe derivada. Este processo é conhecido como

downcasting de ponteiro.

Mais pode causar problemas, já que o ponteiro deve ser derreferenciado, mais ele continua apontando para um objeto. LOGO, fazer um downcasting de um ponteiro de uma classe base para classe derivada e tentar executar uma função da classe derivada pode resultar em erros durante a execução.

O inverso do downcasting é o upcasting ( HAaaa HA ).

Exemplo:

#include <iostream>

class Pai {
  protected:
    int numero;

  public:
    void setNumero( int );
    int getNumero();
};

void Pai::setNumero( int i )
{
  this->numero = i;
}

int Pai::getNumero()
{
  return this->numero;
}

class Filho : public Pai {

  public:
    Filho( int );
    void setNumero( int i );
    int getNumero();
};

Filho::Filho( int i )
{
  this->setNumero( i );
  std::cout << this->getNumero();
}

void Filho::setNumero( int i )
{
  this->numero = (i + 5);
}

int Filho::getNumero()
{
  return this->numero;
}

int main()
{

  // exemplo de herança
  Filho *aFilho_normal = new Filho(5);
  delete aFilho_normal;

  // iniciei as classes simplesmente para o teste de coerção
  Filho aFilho(10);
  Pai aPai;

  // inicie as variaveis null de ponteiros para teste de coerção
  Filho *ptr_filho = 0;
  Pai *ptr_pai = 0;

  // normal
  ptr_filho = &aFilho;
  std::cout << ptr_filho->getNumero() << std::endl;

  // coerção
  // converte filho para pai
  ptr_filho = static_cast< Filho * >( ptr_pai );

  std::cout << ptr_filho->getNumero() << std::endl;

  // PERIGOSO, trata um PAI como um FILHO
  ptr_pai = &aFilho;

  // coerção
  // converte filho( que é pai ) para filho,
  // só que usando o ponteiro pai que agora é filho
  ptr_filho = static_cast< Filho * >( ptr_pai );
  std::cout << ptr_filho->getNumero() << std::endl;

  system("pause");

  return 0;
}

  /// da uns paus fudidos
  // versão 2

#include <iostream>

class Pai {
  protected:
    int numero;

   public:
     Pai( int );
     void setNumero( int );
     int getNumero();
};

Pai::Pai( int i=0 )
{
   this->numero = i;
}

void Pai::setNumero( int i )
{
  this->numero = i;
}

int Pai::getNumero()
{
   return this->numero;
}

class Filho : public Pai {

  public:
    Filho( int );
    void setNumero( int i );
    int getNumero();
};

Filho::Filho( int i )
: Pai( i ) // construtor de pai
{
  this->setNumero( i );
  std::cout << this->getNumero();
}

void Filho::setNumero( int i )
{
   this->numero = (i + 5);
}

int Filho::getNumero()
{
  return this->numero;
}

int main()
{

   // exemplo de herança
  Filho *aFilho_normal = new Filho(5);
  delete aFilho_normal;

  // iniciei as classes simplesmente para o teste de coerção
  Filho aFilho(10);
  Pai aPai();

  // inicie as variaveis null de ponteiros para teste de coerção
  Filho *ptr_filho = 0;
  Pai *ptr_pai = 0, *ptr_pai_original = 0;

  // normal
  ptr_filho = &aFilho;
  std::cout << " - " << ptr_filho->getNumero() << std::endl;

  // coerção
  // converte filho para (pai convertido para filho )
  ptr_filho = static_cast< Filho * >( ptr_pai );

  std::cout << ptr_filho->getNumero() << std::endl;

  // PERIGOSO, trata um PAI como um FILHO
  //ptr_pai = &aPai; vi que no visual c++ isso nao funciona
  //entao vou mudar em baixo

  // coerção
  // converte filho( que é pai ) para filho,
  // só que usando o ponteiro pai que agora é filho
  //ptr_filho = static_cast< Filho * >( ptr_pai );
  //std::cout << ptr_filho->getNumero() << std::endl;


  // coerção
  // converte filho( que é pai ) para filho,
  // só que usando o ponteiro pai que agora é filho
  ptr_filho = static_cast< Filho * >( ptr_pai_original );
  std::cout << ptr_filho->getNumero() << std::endl;

  system("pause");

  return 0;
}

 // ainda dá pau!

//***
exemplo que funciona nessa porra
*/

#include <iostream>

class Pai {
  private:
    int i;

  public:
    Pai( int );
    int getI();
};

class Filho : public Pai {
  public:
    Filho( int );
};

Pai::Pai( int a )
{
  this->i = a;
}

int Pai::getI()
{
  return this->i;
}

Filho::Filho( int a ) : Pai( a )
{

}

int main()
{
  Pai *ptr_pai = 0;
  Filho *ptr_filho = 0;

  Pai aPai(5);
  Filho aFilho(10);

  ptr_filho = &aFilho;
  ptr_pai = &aPai;

  std::cout << ptr_filho->getI() << std::endl;

  ptr_filho = static_cast< Filho * >( ptr_pai );

  std::cout << ptr_filho->getI() << std::endl;

  system("pause");
  return 0;
}

Acredito que o problema dos primeiros exemplos é que nao consegui iniciar ptr_pai.
Logo, ptr_pai está apontando para um lugar qualquer da memoria.

Com herança public, é sempre válido atribuir o ponteiro de uma classe derivada a um ponteiro de uma classe base,
porque um objeto de uma classe derivada é um objeto da classe base. O ponteiro para a classe base ve somente o
os publics da classe base.

Um ponteiro da classe base não pode ser atribuido diretamente a um ponteiro da classe derivada.
Por isso no vc++ ele não deixa fazer, em alguns compiladores isso deve funcionar.

 


- Estudo de Caso: Herança e conversão com mais de um arquivo

/**
Arquivo: peao.h
Autor : Akuma
*/

#ifndef PEAO_H
#define PEAO_H

#include <iostream>

#include "personagem.h"

class Peao : public Personagem {

   friend std::ostream operator<<( std::ostream &, Peao & );

   private:
     int forca;

   public:
     Peao ( int forca, int vx, int vy, int vlife );
     void setForca( int f );
};

#endif

 

 

/**
Arquivo: peao.cpp
Autor : Akuma
*/
#include "peao.h"

Peao::Peao( int forca=0, int vx=0, int vy=0, int vlife=0 )
: Personagem( vx, vy, vlife )
{
  this->forca = forca;
}

void Peao::setForca( int f )
{
  this->forca = f;
}

std::ostream operator<<( std::ostream &c, Peao &p )
{
  c << "Peao Forca > " << p.forca << std::endl;

  return c;
}

 

 

 

/**
Arquivo: personagem.h
Autor : Akuma
*/

#ifndef H_PERSONAGEM
#define H_PERSONAGEM

#include <iostream>

class Personagem {

  friend std::ostream & operator<<( std::ostream &, Personagem & );

  private:
    int x;
    int y;
    int life;

  public:
    Personagem( int x, int y, int life );

  void setX( int x );
  void setY( int y );
  void setLife( int life );

};

#endif

/**
Arquivo: personagem.cpp
Autor : Akuma
*/
#include <iostream>
#include "personagem.h"

Personagem::Personagem( int x=0, int y=0, int life=10 )
{
  this->x = x; 
  this->y = y;

  this->life = life;
}

void Personagem::setX( int x=0 )
{
  this->x = x;
}

void Personagem::setY( int y=0 )
{
  this->y = y;
}

void Personagem::setLife( int life )
{
  this->life = life;
}

std::ostream &operator<<( std::ostream &c, Personagem &p )
{
  c << "x: " << p.x << std::endl;
  c << "y: " << p.y << std::endl;

  c << "Life: " << p.life << std::endl;

  return c;
}

 

 

/**
Arquivo: rei.h
Autor : Akuma
*/

#ifndef REI_H
#define REI_H

#include "peao.h"

class Rei : public Peao {

  friend std::ostream operator<<( std::ostream &, Rei & );

  private:
    int magia;

  public:
    Rei( int vforca, int vx, int vy, int vlife );
    void setMagia();

};

#endif

/**
Arquivo: rei.cpp
Autor : Akuma
*/

#include "rei.h"

Rei::Rei( int vforca=0, int vx=0, int vy=0, int vlife=0 )
: Peao( vforca, vx, vy, vlife )
{
  this->magia = 0;
  this->setForca( 15 );
}

void Rei::setMagia()
{
  this->magia += 1;
}

std::ostream operator<<( std::ostream &c, Rei &rei )
{

  c << ":: REI :: " << std::endl;
  c << "Magia > " << rei.magia << std::endl;

  return c;
}

 

 

/**
Arquivo principal
Autor : Akuma
*/

#include <iostream>

#include "personagem.h"
#include "peao.h"
#include "rei.h"

int main()
{
  Personagem aPlayer(0,0,10);
  Peao aPeao( 10, 0, 0, 10 );
  Rei aRei( 10, 0, 0, 10 );

  Peao *peao = 0;

  std::cout << aPlayer;

  std::cout << aPeao;

  aRei.setMagia();
  std::cout << aRei;

  std::cout << "" << std::endl;
  
  // conversao de rei para peao
  peao = &aRei;

  // agora peao só ve o que tem em peao, e vai chamar o sobrecarregado de peao
  std::cout << *peao;

  system("pause");

  return 0;
}