Aplicação em C++ ( Trabalhando com Classes/Objectos )

o codigo está bem, não tens mais nenhum const em nenhuma declaração/definição de ::inicializar() ?
basicamente ele diz que estas a usar os metodos:

Pessoa::inicializar() const
Funcionario::inicializar() const

sem tarem definidos (que algures no projecto ainda usas esses metodos com a versão const).
 
Última edição:
*A falha foi minha :(

Uma dúvida, que até pode ser parva mas sempre fico esclarecido.

PHP:
private:
           std::string nome;
           void inicializar();

Se eu identifico aqui a variável nome como string.

PHP:
void Pessoa::inicializar()
{
     string nome;
     cout << "Qual o nome da pessoa? " << endl;
     cin >> nome;
     this->alterarNome(nome);
     this->escrever();
}

Aqui é necessário criar a string nome? Bem já vi que está mal criada mas mesmo com std::string o erro continua.
 
o codigo está bem, não tens mais nenhum const em nenhuma declaração/definição de ::inicializar() ?
basicamente ele diz que estas a usar os metodos:

Pessoa::inicializar() const
Funcionario::inicializar() const

sem tarem definidos (que algures no projecto ainda usas esses metodos com a versão const).

Foi isso que andei a ver mas não acho nada, será que posso apagar os ficheiros do projecto .o, .layout e .win e voltar a compilar para ver se o erro desapareçe?

Já no outro deu esse problema e eu não achei nada que utiliza-se tal coisa, como solução voltei a criar outro projecto, senão poder fazer o que disse antes eu crio outro.
 
xii nem reparei, lol.
não precisas de std:: já declaraste o namespace.

quando fazes: cin >> nome; ele guarda no nome da propria classe (definido dentro do private, se não tiveres uma variavel com esse nome definida no proprio metodo, o que n e o teu caso).
mas outra coisa: no teu caso tu declaraste string nome; no proprio metodo, e ele no cin devia dar prioridade a essa variavel em vez de escrever directamente no nome da propria classe, portanto o teu codigo continua correcto.

que compilador/IDE tas a usar? isso é capaz de ter um "clean solution" ou "clean project".
 
Última edição:
xii nem reparei, lol.
não precisas de std:: já declaraste o namespace.

quando fazes: cin >> nome; ele guarda no nome da propria classe (definido dentro do private).

que compilador/IDE tas a usar? isso é capaz de ter um "clean solution" ou "clean project".

Estou a utilizar o Dev-C++ e procurei por isso e não achei nada. O Visual C++ 2005 Express Edition bloqueia cada vez que o inicio :(
 
sendo assim (e como dizes que funcionou da outra vez) tenta criar um projcto novo. pode ser o proprio dev c++ a atrufiar.

se não der, posta o projecto completo.
 
Afinal tinha aqui o Recompilar Tudo que funcionou perfeitamente.

Agora há um novo problema. .

ps1.gif


Mas pelo menos já está a escrever :D Alguma coisa positiva :)

Consegui resolver qualquer coisa. . :)

Antigo main()

PHP:
int main(int argc, char *argv[])
{
    Pessoa AP[999];
    int numeroElementos = 0;
    
    Funcionario FuncionarioNovo(0);
    AP[numeroElementos] = FuncionarioNovo;
    
    AP[0].escrever();
    
    numeroElementos++;
         
    system("PAUSE");
    return EXIT_SUCCESS; 
}

Novo main()

PHP:
int main(int argc, char *argv[])
{
    //Pessoa AP[999];
    int numeroElementos = 0;
    
    Funcionario FuncionarioNovo(0);
    //AP[numeroElementos] = FuncionarioNovo;
    
    //AP[0].escrever();
    
    //numeroElementos++;
         
    system("PAUSE");
    return EXIT_SUCCESS; 
}

Curiosamente ele pede o nome da pessoa, lê-o, escreve-o e acaba. :O

Classe Pessoa

PHP:
Pessoa::Pessoa(void): nome("")
{
     this->inicializar();
}
void Pessoa::inicializar()
{
     cout << "Qual o nome da pessoa? " << endl;
     cin >> nome;
     this->alterar(nome);
     this->escrever();
}

Classe Funcionario

PHP:
Funcionario::Funcionario(void): numeroDeIdentificacaoNaEmpresa(0)
{
     this->inicializar();
}
void Funcionario::inicializar()
{
     Pessoa PessoaNovo("");
     cout << " Qual o numero de identificacao? " << endl;
     cin >> numeroDeIdentificacaoNaEmpresa;
     this->alterar(numeroDeIdentificacaoNaEmpresa);
     this->escrever();
}
 
Última edição:
claro, sempre que fazes:

Pessoa p;
Funcionario f;

ele constroi esses objectos chamando o constructor por default, esteja ele definido ou não.
o teu proprio constructor por default (que tu tens definido para ambas as classes) chama o metodo ::Inicializar() que pede uma string como input e faz o que têm a fazer.

basta fazeres:

Pessoa p;

que internamente ele faz:

Pessoa:: Pessoa()
Pessoa::Inicializar()

outra coisa, se fizeres:

Pessoa p[999];

ele constroi 999 objectos, e pede o nome 999 vezes (outra vantagem de usar vector) :p
 
claro, sempre que fazes:

Pessoa p;
Funcionario f;

ele constroi esses objectos chamando o constructor por default, esteja ele definido ou não.
o teu proprio constructor por default (que tu tens definido para ambas as classes) chama o metodo ::Inicializar() que pede uma string como input e faz o que têm a fazer.

basta fazeres:

Pessoa p;

que internamente ele faz:

Pessoa:: Pessoa()
Pessoa::Inicializar()

outra coisa, se fizeres:

Pessoa p[999];

ele constroi 999 objectos, e pede o nome 999 vezes (outra vantagem de usar vector) :p

Ok, percebidissimo :D

Agora o problema é..

PHP:
Funcionario FuncionarioNovo(0);

ele vai saltar para..

PHP:
Funcionario::Funcionario(void): numeroDeIdentificacaoNaEmpresa(0)
{
     this->inicializar();
}

e posteriormente ele vai para..

PHP:
void Funcionario::inicializar()
{
     Pessoa PessoaNovo("");

que passa em..

PHP:
Pessoa::Pessoa(void): nome("")
{
     this->inicializar();
}
void Pessoa::inicializar()
{
     cout << "Qual o nome da pessoa? " << endl;
     cin >> nome;
     this->alterar(nome);
     this->escrever();
}

mas depois aqui termina e a ideia é pedir o número :(
Que supostamente ia acontecer se volta-se ao Funcionario::inicializar()

PHP:
cout << " Qual o numero de identificacao? " << endl;
     cin >> numeroDeIdentificacaoNaEmpresa;
     this->alterar(numeroDeIdentificacaoNaEmpresa);
     this->escrever();
}
 
Última edição:
ele em Funcionario f(0); não vai para Funcionario::Funcionario(void) mas sim para Funcionario::Funcionario(int);

btw: parametros com void para definir função/metodo sem parametros está deprecated em c++
 
Finalmente dá valores. . :D

Uma dúvida que me surgiu com este ultimo assunto.

PHP:
// class constructor
Pessoa::Pessoa(void): nome("")
{
     this->inicializar();
}
Pessoa::Pessoa(std::string novoNome): nome(novoNome)
{
}

PHP:
// class constructor
Funcionario::Funcionario(): numeroDeIdentificacaoNaEmpresa(0)
{ 
}
Funcionario::Funcionario(unsigned long novoNumeroDeIdentificacao): numeroDeIdentificacaoNaEmpresa(novoNumeroDeIdentificacao)
{
     this->inicializar();
}

Porque é que são diferentes? O que queres dizer com "deprecado"?
 
Desde já, apesar de poder parecer repetitivo, muito obrigado por toda a tua ajuda como também pelo tempo que tem gasto aqui comigo :), tem sido importantissimo. :beerchug:

Estou agora a usar o vector de que me falas-te e até agora está a correr tudo muito bem. Aqui fica o código para darem uma olhadela :)

PHP:
int main()
{
    vector <Pessoa> vec;
    char op;
    
	while (op != 's') 
    {
          cout << "Deseja parar? ( S | N )\n";
          cin >> op;
		  if (op == 's' || op == 'S') break;
		  Funcionario FuncionarioNovo(0);
		  vec.push_back(FuncionarioNovo);
	}
    
    for (int i = 0; i < vec.size(); i++) 
    {
		vec[i].escrever();
    }

    system("PAUSE");
    return EXIT_SUCCESS; 
}

Nenhum problema neste parte. Só estou com um dúvida num dos meus métodos, já tentei de tudo e não consigo escrever() o nome do Funcionário.

PHP:
void Funcionario::escrever(std::ostream& f) const
{
     //Pessoa.escrever();
     f << numeroDeIdentificacaoNaEmpresa << " ";
     f << std::endl;
}

Está em comentado, porque não conseguia testar o resto e para não ficar preso a isso comentei, se poderes dar uma ajuda, mais uma vez te agradeço. :D Entretanto vou colocar o projecto como estava antes.
 
Última edição:
Já se começa a perceber qualquer coisa :D

ps2.gif


Fiz esta imagem para te mostrar os erros que estão a ocorrer ( uma imgem vale mais que 1000 palavras ) :D

Código da Listagem

PHP:
else if ( op == "L" )
        {
		      for (int i = 0; i < vec.size(); i++) 
              {
                       vec[i].escrever();
       	      }
       	      system("PAUSE");
        }

Pelo que percebi com tudo o que me explicas-te até agora ( até já estive que podia ter-me escapado de alguma coisa :( ) ele não vai ao método escrever do Funcionário ou Visitante?

Pelo que parece está a ir só ao método escrever() da classe Pessoa.

Uma coisa que também está acontecer, mas que é menos relevante é ele apenas ler o primeiro nome, como podes ver na 3ª inserção, ele depois devolve apenas o primeiro nome :S

PHP:
void Pessoa::inicializar()
{
     cout << "\nQual o nome da pessoa? ";
     fflush(stdin);
     cin >> nome;
     // cout << nome; Primeiro
     this->alterar(nome);
}
void Pessoa::alterar(std::string novoNome)
{
	nome = novoNome;
	//cout << nome; Segundo
}

Coloquei esses couts para ir testando mas em ambos o output é apenas o primeiro nome.
 
se calhar o melhor era fazer um vector de Funcionario em vez de Pessoa, visto que o Funcionario é que deriva da Pessoa.

o que tu queres é no método ::escrever() do funcionario chamar também o metodo escrever da Pessoa (class base) certo?

void Funcionario::escrever(std:: ostream& f) const
{
this->Pessoa::escrever(f);
f << numeroDeIdentificacaoNaEmpresa << " ";
f << std::endl;
}

voilá :p

outra coisa, o cin >> string só vai buscar até encontrar um espaço, tab, return. portanto o ideal é usar a função getline(), em vez de:
cin >> nome
fazes
getline( cin, nome ); (a função faz parte do standard).


PHP:
// class constructor
Pessoa::Pessoa(void): nome("")
{
     this->inicializar();
}
Pessoa::Pessoa(std::string novoNome): nome(novoNome)
{
}

PHP:
// class constructor
Funcionario::Funcionario(): numeroDeIdentificacaoNaEmpresa(0)
{ 
}
Funcionario::Funcionario(unsigned long novoNumeroDeIdentificacao): numeroDeIdentificacaoNaEmpresa(novoNumeroDeIdentificacao)
{
     this->inicializar();
}

Porque é que são diferentes? O que queres dizer com "deprecado"?

metodos com o mesmo nome mas parametros diferentes, sao metodos diferentes, têm assinaturas diferentes e para o compilador, cpu, SO, whatever vao se coisas completamente diferentes e não há nada a fazer :p

quanto a deprecated, quer dizer que é aceite mas já não fz parte do standard. se amanha metessem o gcc a não aceitar isso (o g++ pelo menos), o compilador tava bom na mm :p
 
Ui, Perfeito ;) Muito Obrigado :)

Já tratei de reaproveitar o código do projecto anterior ( aquele que deu erro! ) e está tudo a funcionar excepto o que vou colocar de seguida.

O projecto é uma empresa, com as seguintes classes:

  • Funcionario
  • Visitante
  • Director

Eu acrescentei a classe Pessoa, sendo assim ( e acrescentando as heranças ):

  • Pessoa
    • Funcionario
      • Director
    • Visitante

O código é o seguinte:

PHP:
class Director : public Funcionario
{
      private:
             std::string departamento;
             void inicializar();
	  public:
		     // Métodos Públicos
		     Director(void);
    		 // class constructor
             Director(std::string novoDepartamento);
    		 // class destructor
    		 ~Director();
    		
             virtual std::string obtemDepartamento() const;
           
             virtual void alterar(std::string novoDepartamento);
             virtual void escrever(std::ostream& f=std::cout) const;
             virtual void listar(std::ostream& f=std::cout) const;
};
PHP:
Director::Director(void): departamento("")
{
     this->inicializar();
}
void Director::inicializar()
{
     Funcionario FuncionarioNovo(0);
     cout << "\n  Qual o nome do departamento? ";
     fflush(stdin);
     getline( cin, departamento );
     this->alterar(departamento);
}

PHP:
Funcionario::Funcionario(unsigned long novoNumeroDeIdentificacao): numeroDeIdentificacaoNaEmpresa(novoNumeroDeIdentificacao)
{
     this->inicializar();
}
void Funcionario::inicializar()
{
     Pessoa PessoaNovo("");
     cout << "\n  Qual o numero de identificacao? ";
     fflush(stdin);
     cin >> numeroDeIdentificacaoNaEmpresa;
     this->alterar(numeroDeIdentificacaoNaEmpresa);
}

Sabendo que o Director herda da classe Funcionario e este último herda da classe Pessoa, o código acima deveria estar correcto, ou será que me está a escapar alguma coisa?

O problema é o seguinte, quando eu inserir um determinado Director ele pelo que está no código deveria:

  • Criar uma pessoa, pedir nome; ( Pessoa PessoaNovo(""); )
  • Criar um funcionário, pedir número; ( Funcionario FuncionarioNovo(0); )
  • Criar um director e pedir o departamento; ( Director departamento(""); )

Mas não está a acontecer isso. :(

ps3.gif


Código

PHP:
else if ( op == "V" )
        {
              cout << "\n  Inserindo novo Visitante \n";
		      Visitante VisitanteNovo(0);
		      vecVisitante.push_back(VisitanteNovo);
		      while ( op != "S" )
              {
                    op = menus("TratarPessoa", "Visitante");
                    tratarVisitante( op, VisitanteNovo );
              }
              op = "";
        }
PHP:
else if ( op == "D" )
        {
              cout << "\n  Inserindo novo Director \n";
		      Director DirectorNovo("");
		      vecDirector.push_back(DirectorNovo);
		      while ( op != "S" )
              {
                    op = menus("TratarPessoa", "Director");
                    tratarDirector( op, DirectorNovo );
              }
              op = "";
        }

Depois também estou com umas dúvidas na parte em que vou alterar um determinado objecto mas é melhor fazer uma coisa de cada vez para ficar bem percebido.

Obrigado por tudo. :cool:
 
Última edição:
Boas.
Ao que parece, o problema está no construtor de director. Ao instanciares um director, o seu constructor inicia os campos pertencentes a director e evoca o construtor, caso esteja definido, da sua base (senão o construtor por omissão), para iniciar os campos herdados. Talvez fosse melhor, tanto em Director como no resto das classes, extraires 1º os dados só depois evocares o construtor. Tornas assim o código mais robusto pois o construtor só é evocado se o utilizador tiver inserido dados válidos.
Já agora, o construtor da classe base evoca-se da mesma forma que fazes para afectar os campos de instância na chamada ao construtor.

Código:
std::string nome = "xpto";

Director::Director(const std::string nome&, int ident ): Funcionario(nome), id(ident){}

Podes depois, no corpo do construtor evocar o método inicializar como complemento, para informação não tão relevante.


Já agora, outra sugestão. Quanto á estrutura de dados que estás a utilizar, deverias optar por um contentor associativo (um map por exemplo) em que a chave poderia ser o numero do bi, pois é único. Isto torna as pesquisas e remoções mais eficiênces, embora ao contrário do vector, a inserção não seja em tempo constante.

Cumprimentos.
 
Última edição:
Boas.
Ao que parece, o problema está no construtor de director. Ao instanciares um director, o seu constructor inicia os campos pertencentes a director e evoca o construtor, caso esteja definido, da sua base (senão o construtor por omissão), para iniciar os campos herdados. Talvez fosse melhor, tanto em Director como no resto das classes, extraires 1º os dados só depois evocares o construtor. Tornas assim o código mais robusto pois o construtor só é evocado se o utilizador tiver inserido dados válidos.

Mas segundo o que percebi no desenvolvimento deste tópico, o construtor é chamado sempre que criamos um determinado Directo, por exemplo, ou estou errado.

Tendo em conta que disses-te deverei fazer algo do género...

PHP:
// class constructor
Director::Director(void): departamento("")
{
     this->inicializar();
}
Director::Director(std::string novoDepartamento): departamento(novoDepartamento)
{ }
void Director::inicializar()
{
     Funcionario FuncionarioNovo(0);
     getline( cin, departamento );
     this->alterar(departamento);
}

PHP:
cout << "\n  Inserindo novo Director \n";
cout << "Nome do novo Director?";
fflush(stdin);
getline( cin, nome );
cout << "Número interno do novo Director?";
fflush(stdin);
cin >> numIden;
cout << "Nome do departamento do novo Director?";
fflush(stdin);
getline( cin, departamento );
Director DirectorNovo("");
vecDirector.push_back(DirectorNovo);
while ( op != "S" )
{
        op = menus("TratarPessoa", "Director");
        tratarDirector( op, DirectorNovo );
}
op = "";

Já agora, o construtor da classe base evoca-se da mesma forma que fazes para afectar os campos de instância na chamada ao construtor.

Código:
std::string nome = "xpto";

Director::Director(const std::string nome&, int ident ): Funcionario(nome), id(ident){}

Podes depois, no corpo do construtor evocar o método inicializar como complemento, para informação não tão relevante.

Não percebi muito bem. :S

Já agora, outra sugestão. Quanto á estrutura de dados que estás a utilizar, deverias optar por um contentor associativo (um map por exemplo) em que a chave poderia ser o numero do bi, pois é único. Isto torna as pesquisas e remoções mais eficiênces, embora ao contrário do vector, a inserção não seja em tempo constante.

Eu pensei nisso mas acabei por pôr de lado, devido aos dados não serem iguais para todos..

Funcionario - Número de identificação na empresa.
Visitante - Número do bilhete de identidade.
Director - Herda do funcionário o número de identificação na empresa.

Muito obrigado pela tua ajuda :D

Situação actual do projecto:

Classe Pessoa

PHP:
class Pessoa
{
    private:
           std::string nome;
           void inicializar();
    public:    
           // Métodos Públicos
           Pessoa(void);
           // class constructor
           Pessoa(std::string novoNome);
           // class destructor
           ~Pessoa(void);
           
           virtual std::string obtemNome() const;
           
           virtual void alterar(std::string novoNome);
           virtual void escrever(std::ostream& f=std::cout) const;
           virtual void listar(std::ostream& f=std::cout) const;
};

Pessoa::Pessoa(void): nome("")
{
     this->inicializar();
}
Pessoa::Pessoa(std::string novoNome): nome(novoNome)
{}
void Pessoa::inicializar()
{
     cout << "\n  Qual o nome da pessoa? ";
     fflush(stdin);
     getline( cin, nome );
     this->alterar(nome);
}

Classe Funcionario

PHP:
class Funcionario: public Pessoa
{
      private:
             unsigned long numeroDeIdentificacaoNaEmpresa;
             void inicializar();
	  public:
		     // Métodos Públicos
		     Funcionario();
    		 // class constructor
             Funcionario(unsigned long novoNumeroDeIdentificacao);
    		 // class destructor
    		 ~Funcionario();
    		
    		 virtual unsigned long obtemNumeroDeIdentificacao() const;
    		 
             virtual void alterar(unsigned long numeroDeIdentificacao);
             virtual void escrever(std::ostream& f=std::cout) const;
             virtual void listar(std::ostream& f=std::cout) const;
};

// class constructor
Funcionario::Funcionario(): numeroDeIdentificacaoNaEmpresa(0)
{ }
Funcionario::Funcionario(unsigned long novoNumeroDeIdentificacao): numeroDeIdentificacaoNaEmpresa(novoNumeroDeIdentificacao)
{
     this->inicializar();
}
void Funcionario::inicializar()
{
     Pessoa PessoaNovo("");
     cout << "\n  Qual o numero de identificacao? ";
     fflush(stdin);
     cin >> numeroDeIdentificacaoNaEmpresa;
     this->alterar(numeroDeIdentificacaoNaEmpresa);
}

Classe Visitante

PHP:
class Visitante : public Pessoa
{
      private:
             unsigned long numeroDoBilheteDeIdentidade;
             void inicializar();
	  public:
		     // Métodos Públicos
		     Visitante(void);
    		 // class constructor
             Visitante(unsigned long novoNumeroDoBI);
    		 // class destructor
    		 ~Visitante();
    		
    		 virtual unsigned long obtemNumeroDoBilheteDeIdentidade() const;
           
             virtual void alterar(unsigned long novoNumeroDoBI);
             virtual void escrever(std::ostream& f=std::cout) const;
             virtual void listar(std::ostream& f=std::cout) const;
};

// class constructor
Visitante::Visitante(void): numeroDoBilheteDeIdentidade(0)
{ }
Visitante::Visitante(unsigned long novoNumeroDoBI): numeroDoBilheteDeIdentidade(novoNumeroDoBI)
{
     this->inicializar();
}
void Visitante::inicializar()
{
     Pessoa PessoaNovo("");
     cout << "\n  Qual o numero do bilhete de identidade? ";
     fflush(stdin);
     cin >> numeroDoBilheteDeIdentidade;
     this->alterar(numeroDoBilheteDeIdentidade);
}

Classe Director

PHP:
class Director : public Funcionario
{
      private:
             std::string departamento;
             void inicializar();
	  public:
		     // Métodos Públicos
		     Director(void);
    		 // class constructor
             Director(std::string novoDepartamento);
    		 // class destructor
    		 ~Director();
    		
    		 virtual std::string obtemDepartamento() const;
           
             virtual void alterar(std::string novoDepartamento);
             virtual void escrever(std::ostream& f=std::cout) const;
             virtual void listar(std::ostream& f=std::cout) const;
};

// class constructor
Director::Director(void): departamento("")
{
     this->inicializar();
}
Director::Director(std::string novoDepartamento): departamento(novoDepartamento)
{ }
void Director::inicializar()
{
     Funcionario FuncionarioNovo(0);
     cout << "\n  Qual o nome do departamento? ";
     fflush(stdin);
     getline( cin, departamento );
     this->alterar(departamento);
}
 
Viva.
O construtor da classe base é evocado, mas se pretendes evocar explicitamente, passando-lhe parametros, não podes faze-lo através de uma terceira função. Se queres instanciar um director e evocar tambem o construtor da sua classe base (Funcionário), terás de o fazer em frente á assinatura do construtor, tal como inicias os campos de instância. Isto foi em seguimento áquelas sugestões. Recebe primeiro em variáveis auxiliares os dados do director e outros e só depois evocas o construtor. Não vale a pena instânciares um director sem ter primeiro os dados.

função main

Código:
int main (int argc, std::string argv[])
{
//Tendo os dados ja extraidos de istreams em variaveis auxiliares:
std::string nome = "John";
std::string morada = "Av da Liberdade";
int numFuncionario = 000;
std::string dep = "Vendas";

    Pessoa* p = new Director(nome, morada", 000, dep);
}
Supondo que o director so tem o campo departamento.
O director é uma pessoa, logo tem uma morada e um nome (herdados de funcionario que por sua vez herdou de pessoa). Também é um funcionario e como tal tem um numero de funcionario (000) (herdado tambem de funcionario). Todos estes construtores tem de ser evocados se queres afectar logo os campos.

Director.cpp
Código:
Director::Director(std::string nome&, std::string morada&, int num, std::string& dep) : Funcionario(nome,morada,num), departamento(dep) {}

Funcionario.cpp
Código:
Funcionario::Funcionario(std::string nome&, std::string morada&, int num) : Pessoa(nome,morada), numeroDeFuncionario(num){}
Pessoa.cpp
Código:
Pessoa(std::string nome&, std::string morada&):nome(nomePessoa), morada(morada) {}

Como podes ver, os construtores sao evocados de forma digamos que "recursiva".

Em relação ás chaves do map que sugeri, isso resolvia-se utilizando um dos conceitos da programação Object Oriented que é o polimorfismo. Mas posso estar para aqui a falar de conceitos que não estão no objectivo que o professor pretende com o trabalho. Se estiver a ir longe diz :)

Visto que a classe pessoa nunca é instanciada, apenas serve de base ás outras, pode ser abstracta. Declaras nela um método chamado getId como virtual puro.

Código:
virtual int getId()=0;

Agora, todas as classes na hierarquia serão abstractas até que redifinas esse método herdado em cada uma delas.

funcionario.cpp

int Funcionario::getId()
{
return numeroFuncionario;
}

Director.cpp
//Não precisas de redifinir pois herda esse metodo de funcionario, no qual ja se encontra redefinido

Visitante.cpp

int Visitante::getId()
{
return bilheteId;
}

Desta forma, tendo um mapa de apontadores para a classe mais genérica (Pessoa) podes atraves do polimorfismo evocar o metodo de cada objecto apontado

Código:
Pessoa *p = new Director("joao", "av das ostras", 000, "Vendas");
Pessoa *x = new Visitante("rui", 9898);

std::cout << p->getId() << std::endl; // evoca o getId de director, o qual devolve o numero de funcionario

std::cout << x->getId() << std::endl //evoca o getId de visitante, o qual devolve o numero de bi

Como podes ver, este conceito permite atraves de apontadores do mesmo tipo evocar metodos diferentes, pois não é evocado metodo referente ao tipo do apontador mas sim ao tipo do objecto apontado. Assim consegues pesquisar no mapa ou listar os elementos chamando o metodo getId().

Cumprimentos
 
Última edição:
Muito Obrigado

Boas :D,

Desde já obrigado pelo trabalho que estás a ter e por todas a explicações! ;)

Quanto ao assunto de alterar os constructores, como deves imaginar para mim ainda é complicado apanhar logo tudo de uma vez e achar o melhor método mas pelo que li penso que tem lógica fazer da maneira que me estás a dizer. Não quero com isto desprezar o trabalho o sapropel teve ao longo deste tópico ( está tudo percebido ;) ).

Eu só queria que me explicassem uma coisa que me está a atrofiar e ainda não perguntei por "vergonha", é assim:
PHP:
// class constructor ( Ficheiro - Pessoa.h )
Pessoa(std::string novoNome );

// class constructor  ( Ficheiro - Pessoa.cpp )
Pessoa::Pessoa(void): nome("") { }
Pessoa::Pessoa(std::string novoNome): nome(novoNome) { }

Estes dois métodos, foram tirados de um projecto que a prof. das prácticas esteve a desenvolver na aula ( tinha de começar por algum lado :( ) mas não estou a ver as diferenças de um método para o outro. Sei que um é o constructor, o qual inicializa o nome como vazio, neste caso:

PHP:
// class constructor  ( Ficheiro - Pessoa.cpp )
Pessoa::Pessoa(void): nome("") {}

Então qual a necessidade do segundo?

PHP:
Pessoa::Pessoa(std::string novoNome): nome(novoNome) { }

Desculpem mas acho que mais vale perceber realmente o que cada coisa faz e para que serve, assim talvez deixe de ter alguma dúvidas "parvas".
Continuando a assunto de deixar de chamar a função inicializar(), tendo em conta o que li penso que quanto ao que tenho aqui ficaria assim:

PHP:
// class constructor ( Ficheiro - Pessoa.h )
Pessoa(std::string nome&/*, std::string morada&*/);
// class constructor  ( Ficheiro - Pessoa.cpp )
Pessoa::Pessoa(void): nome("") {}
Pessoa(std::string nome&/*, std::string morada&*/):nome(nomePessoa)/*, morada(morada)*/ {}

PHP:
// class constructor ( Ficheiro - Funcionario.h )
Funcionario(std::string nome&, int num);
// class constructor  ( Ficheiro - Funcionario.cpp )
Funcionario::Funcionario(): numeroDeIdentificacaoNaEmpresa(0){ }
Funcionario::Funcionario(std::string nome&/*, std::string morada&*/, int num) : Pessoa(nome/*,morada*/), numeroDeFuncionario(num){}

PHP:
// class constructor ( Ficheiro - Director.h )
Director(std::string nome&/*, std::string morada&*/, int num, std::string& dep);
// class constructor  ( Ficheiro - Director.cpp )
Director::Director(void): departamento("") { }
Director::Director(std::string nome&/*, std::string morada&*/, int num, std::string& dep) : Funcionario(nome/*,morada*/,num), departamento(dep) {}

*Não vou colocar por enquanto a morada para primeiro perceber isto como deve ser :)

Estou correcto?

Quanto ao polimorfismo, também foi um dos conceitos dados na aula mas pelos visto mal aprendido :S

Só não percebi o que queres dizer com uma class abstracta e com o virtual puro.

Aqui - "Visto que a classe pessoa nunca é instanciada, apenas serve de base ás outras, pode ser abstracta. Declaras nela um método chamado getId como virtual puro."

De resto está tudo percebido, só preciso desta explicações e penso que poderei avançar :)
 
Boas. Os construtores são funções. Podes ter vários definidos para o mesmo tipo, desde que difiram no numero e tipo de parametros como é o caso desses dois. Distinguem-se pois um não recebe parametros e o outro recebe uma string. Para que é que serve?

No caso de quereres iniciar uma instância de pessoa com um nome, podes passar como parametro ao construtor.

main:

Código:
std::string nome;
std::cout << "insira o nome:\n";
std::cin >> nome;

pessoa *p1 = new Pessoa(nome); //neste caso o construtor a ser evocado é o construtor que recebe uma string

pessoa *p2 = new Pessoa(); //é evocado o construtor sem parametros

Na 2a instância, o atributo nome de p1 ficará com "", pois segundo a implementação do construtor sem parametros que fizeste, caso nao se passem parametros, o nome corresponderá a uma string vazia. Não é que um construtor com parametros seja indispensável... podes sempre afectar os campos mais tarde, mas isto, obrigaria a que todos os campos fossem de acesso público ou houvessem funções membro para afectar todos os campos, desprezando o conceito de encapsulamento, levando a graves falhas de segurança.


Uma classe abstracta não pode ser instânciada. Pode-se dizer que é uma classe que existe apenas para servir métodos e campos ás suas derivadas. Que nunca necessirarás de instanciar. Utilizando o teu exercicio, supoe que não estavas a utilizar uma classe pessoa e cada uma das classes que estas a utilizar definiam os seus proprios campos:

Visitante:
-nome
-morada
-bi

Funcionario:
-nome
-morada
-numfuncionario

Director:
-nome
-morada
-numFuncionario
-departamento


Assim terias um programa muito mais complexo e de dificil actualização. Se pretendesses adicionar uma classe supervisor, lá terias de estar a criar os mesmo campos, havendo muita repetição de código.
Para resolver este problema, tens uma classe pessoa que contem todos os campos comuns a funcionario e director. Mas director difere de funcionario no campo departamento. Então Director define esse campo e deriva de funcionário, pois director é um funcionario da empresa e que por sua vez é uma pessoa. O visitante tambem é uma pessoa e só acrescenta o bi, deriva directamente de Pessoa.


Quanto ao polimorfismo, consiste numa classe derivada modificar o comportamento da base.

No teu exercicio, imaginando que pretendes armazenar os funcionarios, directores e visitantes em contentores.
Terias de ter um vector ou mapa de objectos para tipo funcionario, outro de directores e outro de visitantes. Teriam-se 3 vectores ou maps. :s Era uma chatice para manipular tudo isto. Criar um novo objecto implicaria verificar se era funcionario, visitante ou director, aceder ao respectivo contentor e posteriormente pesquisar, pois ja poderia existir e so depois adicionar.

Para resolver isto pensamos da seguinte forma:
Funcionarios, directores e visitantes são pessoas, não é ? Então criamos um contentor de apontadores para pessoas, ou seja, para a classe mais genérica e colocamos tudo num só. Utilizando o vector como exemplo:

Código:
std::vector<Pessoa*> pessoas;
Pessoa p1 = new Funcionario("Jose");
Pessoa p2 = new Director("Marta");
Pessoa p3 = new Visitante("Joana")
pessoas.push_back(p1);
pessoas.push_back(p2);
pessoas.push_back(p3);
// ou podes instanciar e inserir directamente no vector:
// pessoas.push_back(new Funcionario("Jose"));

Até aqui tudo bem, mas agora supoe que queres um metodo getId() que para funcionarios e directores retorne o numFuncionario e para visitantes retorne o numero do bi. Visto que este método será comum a todas as classes, o melhor é declarar na classe base. Mas isto trás outro problema. Pessoa não tem um campo bi, nem um numFuncionario. É aqui que entra o polimorfismo e os métodos virtuais puros. Declarando o método getId() como virtual puro na classe base, torna a classe abstracta (não pode ser instânciada) e permite realizares chamadas polimorficas sobre apontadores para essa classe.

Pessoa.h
Código:
virtual int getId()=0;
Declarando como virtual puro, obriga a que redifinas nas classes derivadas, ou seja, só podes instanciar um visitante se este tiver definido um metodo getId(). O mesmo se passa com o funcionario/director.

visitante.cpp

Código:
int visitante::getId()
{
   return bi;
}

funcionario.cpp

Código:
int funcionario::getId()
{
   return numFuncionario;
}

director.cpp

Não precisa pois é comum a funcionário.

Assim já poderias evocar o método getId() sobre elementos do vector, que seriam chamados os métodos do tipo do objecto apontado. Continuando o exemplo, pontanto, o 1º elemento do vector é um funcionario, o 2º um director e o 3º é um visitante.
Então:

Código:
pessoas[0]->getId(); //evoca o getId() de funcionario
pessoas[1]->getId(); //evoca o getId() de funcionario
pessoas[2]->getId(); //evoca o getId() de visitante
Isto é, evoca o metodo não segundo o tipo do apontador (que é pessoa) mas segundo o tipo do objecto apontado.

Cumps
 
Back
Topo