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

BOas,

percebi tudo o que disses-te até agora e está tudo a funcionar! Aproveito para agradecer novamente o que voces me explicaram até agora, têm sido 5*. Muito obrigado.

Agora gostava que me esclarecem-se outra dúvida.

Tendo em conta que o conceito de programação orientada a objectos, segundo o que percebi até agora, nos dá uma forte mobilidade quando há necessidade, futuramente, de adicionar novas classes/funções, etc à aplicação em si a minha dúvida é a seguinte:

Voltanto à função inicializar(), a qual actualmente já tirei do código, tendo em conta agora apenas a sua ideia eu achei-a bastante interessante porque tinha-mos os pedidos dos dados na classe a que os dados eram referentes e assim podiamos, futuramente, alterar uma classe e os seus pedidos de dados na mesma, sem ter assim, que alterar quase nada na função main().

Por exemplo, acrescentando a morada na classe pessoa.

Com o código actual, eu teria de ir..

PHP:
std::string nome;
unsigned long num;
cout << "\n  Inserindo novo Funcionário \n";
std::cout << "insira o nome: "; fflush(stdin);
getline ( cin, nome );
std::cout << "insira o num: "; fflush(stdin);
std::cin >> num;
             
Pessoa* f = new Funcionario(nome, num);
Pessoas.push_back(f);

..e colocar..

PHP:
std::string nome//, morada;
             unsigned long num;
             cout << "\n  Inserindo novo Funcionário \n";
             std::cout << "insira o nome: "; fflush(stdin);
             getline ( cin, nome );
             //std::cout << "insira a morada: "; fflush(stdin);
             //getline ( cin, morada );
             std::cout << "insira o num: "; fflush(stdin);
             std::cin >> num;
             
             Pessoa* f = new Funcionario(nome/*, morada*/, num);
             Pessoas.push_back(f);

..e então ir à classe pessoa..

PHP:
//Pessoa.h
// class constructor
           Pessoa(std::string novoNome/*, std::string morada*/);
//Pessoa.cpp
// class constructor
Pessoa::Pessoa(void): nome("") { }
Pessoa::Pessoa(std::string novoNome/*, std::string morada*/): nome(novoNome)/*, morada(novaMorada)*/ { }

..e agora sim teria a alteração feita! Coloquei em comentário as alterações para ser mais facil de visualizar.

Com este código teria que alterar no total em três partes diferentes, no main.cpp, no Pessoa.h e no Pessoa.cpp.

Agora utilizando apenas a ideia que a função inicializar() me deu e o código actual o qual não tem a morada, seria possivel fazer isto:

PHP:
// class constructor
Pessoa::Pessoa(void): nome("")
{
std::cout << "insira o nome: "; fflush(stdin);
getline ( cin, nome );
}
Pessoa::Pessoa(std::string novoNome): nome(novoNome) { }

// class constructor
Funcionario::Funcionario(): numeroDeIdentificacaoNaEmpresa(0)
{
std::cout << "insira o num: "; fflush(stdin);
std::cin >> num;
}
Funcionario::Funcionario(std::string nome, unsigned long num) : Pessoa(nome), numeroDeIdentificacaoNaEmpresa(num){}

e no main.cpp ficaria apenas assim:

PHP:
Pessoa* f = new Funcionario("",0);
Pessoas.push_back(f);

Ou seja para alterar eu apenas teria que mexer "a sério" nas classes, alterando apenas no main.cpp, esta parte:

PHP:
Funcionario("",0);

Sei que isto vai contra o que disso o HavoC:

Não vale a pena instânciares um director sem ter primeiro os dados.

Mas não será muito mais facil futuras alterações, ou isto mexe com mais alguns conceitos?

Cumprimentos,
Nelson Ferreira
 
Boas noites :-)
Eu não disse para não utilizares a função inicializar(). O que sugeri foi, dado o contexto do programa, para não utilizares a função inicializar() no construtor sem parametros. É sempre preferivel primeiro pedires os dados imutaveis do objecto que queres instânciar, como o nome e o id e testar se são validos e só depois instanciar o objecto. Isto garante que todos os objectos que crias são validos e tornas o codigo mais robusto. Senão imagina, evocas o construtor, é reservada memoria dinamicamente e depois o utilizador inseria campos invalidos em nome e id. A memória ja estava reservada. La terias de destruir o objecto. Assim, sempre podes primeiro testar se esse id ou nome já existem e só depois com segurança, evocar o construtor passando-lhe esses parâmetros.
Mas se quiseres utilizar essa função, podes sempre declará-la como virtual (nao puro) em pessoa para conseguires chamadas polimorficas quando quiseres alterar os campos de um objecto e redifinir esse mesmo método em cada uma das outras classes para afectarem os campos que lhe pertencem.

Por exemplo:

pessoa.cpp

Código:
virtual void pessoa::inicializar()
{
   std::cout << "Insira o nome da pessoa:" << std::endl;
   std::cin >> nomePessoa;
}

visitante.cpp

Código:
void visitante::inicializar()
{
   pessoa::inicializar(); //evoca o inicializar de pessoa para afectar os campos comuns a pessoa
   std::cout << "Insira o numero do bi do visitante:" << std::endl;
   std::cin >> numBi; //afecta o campo especifico da classe
}

funcionario.cpp

Código:
void funcionario::inicializar()
{
   pessoa::inicializar(); //evoca o inicializar de pessoa para afectar os campos comuns a pessoa
   std::cout << "Insira o numero de funcionario:" << std::endl;
   std::cin >> numFuncionario; //afecta o campo especifico da classe
}

director.cpp

Código:
void director::inicializar()
{
   funcionario::inicializar(); //evoca o inicializar de funcionario que por sua vez evoca o inicializar de  pessoa
   std::cout << "Insira o departamento:" << std::endl;
   std::cin >> departamento; //afecta o campo especifico da classe
}

Assim podes evocar o método polimorficamente para afectar os campos

main.cpp

Código:
pessoa *p = new director();
p->inicializar();

pessoa *f = new funcionario();
f->inicializar();

pessoa *v = new visitante();
v->inicializar();

Nesta implementação, se chamas o método inicializar() nos construtores, terás redundancias porque o construtor de uma classe derivada evoca o da sua base.
Cumps
 
Última edição:
Bom Dia,

Bem eu só queria perceber bem o porque de não utilizar a função inicializar(). .

Isto garante que todos os objectos que crias são validos e tornas o codigo mais robusto. Senão imagina, evocas o construtor, é reservada memoria dinamicamente e depois o utilizador inseria campos invalidos em nome e id. A memória ja estava reservada. La terias de destruir o objecto. Assim, sempre podes primeiro testar se esse id ou nome já existem e só depois com segurança, evocar o construtor passando-lhe esses parâmetros.

. . ou seja isto, eu gosto de ficar a perceber bem o que estou a fazer e o porque. . Assim vou poupar-vos algumas explicações futuras e acima de tudo fico mesmo a perceber disto. Obrigado pela explicação mais uma vez. ;)

Agora estou com uma dúvida, que já ontem estive devolta disto e não consigo axar o problema >(

PHP:
void Funcionario::alterar(std::string novoNome, unsigned long novoNumeroDeIdentificacao)
{
     this->Pessoa::alterar(novoNome);
     numeroDeIdentificacaoNaEmpresa = novoNumeroDeIdentificacao;
}

PHP:
void Pessoa::alterar(std::string novoNome)
{
	nome = novoNome;
}

No main() coloquei:

PHP:
if( op == "A" )
{
       std::string novoNome;
       unsigned long novoNumeroDeIdentificacao;
                                         
       cout << "\n  Qual o novo nome ( 0 para não alterar )? "; fflush(stdin);
       getline (cin, novoNome);                                         
       cout << "\n  Qual o novo numero de identificacao ( 0 para não alterar )? "; fflush(stdin);
       cin >> novoNumeroDeIdentificacao;
                        
       f->alterar(novoNome,novoNumeroDeIdentificacao);
                                     
       op = "V";
}

Erro 1 -> no matching function for call to `Pessoa::alterar(std::string&, long unsigned int&)'

Ele diz que a função não existe, lá isso é verdade, mas eu quando a chamo só lhe coloco um parametro:
this->Pessoa::alterar(novoNome);

Erro 2 -> virtual void Pessoa::alterar(std::string)

Tentei também desta forma:

this->Pessoa::alterar(std::string novoNome);

Erro 1 - In member function `virtual void Funcionario::alterar(std::string, long unsigned
int)':
expected primary-expression before "novoNome"
 
Boas

Erro 1 -> no matching function for call to `Pessoa::alterar(std::string&, long unsigned int&)'

Ele diz que a função não existe, lá isso é verdade, mas eu quando a chamo só lhe coloco um parametro:
this->Pessoa::alterar(novoNome);

Sim, embora o método alterar de Pessoa so receba um parametro, esta declarado como virtual de maneira que existe polimorfismo. Como existe uma chamada polimorfica sobre Pessoa, o que está a ser evocado é o alterar() mas de funcionário que recebe dois parametros.
Como não sabes quantos campos do objecto queres alterar (se 1 ou 2 ou mesmo todos), tens 2 hipoteses, ou passas todos os parametros á função, colocando por omissão (isto fica foleiro á força toda :P ):

funcionario.cpp

Código:
void Funcionario::alterar(std::string novoNome="", unsigned long novoNumeroDeIdentificacao=0, .......)
{

//teste aos parametros recebidos
if (novoNome != "")
    nome = novoNome;

if (numeroDeIdentificacaoNaEmpresa != 0)
     numeroDeIdentificacaoNaEmpresa = novoNumeroDeIdentificacao;
....
//     this->Pessoa::alterar(novoNome); nen precisas de evocar o alterar das outras classes.
}

Isto é, se não passares um segundo ou terceiro parametro a função coloca "" e 0 respectivamente. Ainda por cima tens de criar tantas funções destas quanto as classes que tens.


Uma outra solução, e bem melhor é utilizares a solução do inicializar() (muda-a para alterar()), do meu reply anterior. Assim, a opção "A" do teu programa evoca o alterar() do respectivo objecto e extrais a informação de istreams dentro da propria função. Podes usar um return ou esse caracter 0 para indicar que nao houve alteração.


pessoa.cpp

Código:
virtual void pessoa::alterar()
{
   std::string novoNome;
   std::cout << "Insira o nome da pessoa:" << std::endl;
   std::cin >> novoNome;

   if (novoNome == "0")
       std::cout << "Nome sem alterações (" << nome << ")" << std::endl;

   else
       nomePessoa = novoNome;
}

funcionario.cpp

Código:
void funcionario::alterar()
{
   pessoa::inicializar();
   unsigned newNum;   
   std::cout << "Insira o numero de funcionario:" << std::endl;
   std::cin >> newNum;

   if (!newNum)
      std::cout << "Numero de funcionario sem alterações (" << numFuncionario << ")" << std::endl;

   else
      numFuncionario = newNum;
}

Cumprimentos
 
Última edição:
Boas

Boas,
acabei por utilizar a segunda opção, pois parece-me muito melhor. :)

Bem já começa a estar pronto, agora estou na fase de implementar o Eliminar uma determinada pessoa.

Estou a seguir o seguinte caminho, mas o qual não está a dar certo:

PHP:
else if ( op == "E" )
{
      cout << "\n  Eliminar Funcionario \n";
      f -> eliminar();
}
// Pessoa.cpp
void Pessoa::eliminar()
{
	delete nome;
}
// Funcionario.cpp
void Funcionario::eliminar()
{
     Pessoa::eliminar();
     delete numeroDeIdentificacaoNaEmpresa;
}

Erro - In member function `virtual void Funcionario::eliminar()': type `long unsigned int' argument given to `delete', expected pointer.

Será que tenho de dar o apontador para o espaço de memória e ai sim, apagar?

Sendo assim bastava fazer algo do género:

PHP:
else if ( op == "E" )
{
     cout << "\n  Eliminar Funcionario \n";
     delete f;
     //Ordenando o vector
     for( n = /*Posição actual*/; n <= Pessoas.size(); n++)
     {
          Pessoas[n-1] = Pessoas[n];                            
     }
     cout << endl;
     system("PAUSE");
}

Ou é mais complexo que isto?

Obrigado mais uma vez por toda a ajuda dada ;)

Com os melhores cumprimentos,
Nelson Ferreira
 
Boa noite.

Exacto, é como fizeste no 2º exemplo. Não precisas desse método eliminar(). So podes fazer delete sobre apontadores para objectos que foram alocados dinamicamente. Nem precisas de definir um destrutor. So terias de o definir se a tua classe tivesse um atributo que fosse um pointer para um objecto alocado dinamicamente (através da palavra chave "new"). Assim, quando o objecto fosse destruído, havia a necessidade de apagar o objecto apontado por esse atributo, porque senão, ficaria um objecto perdido na memória, a ocupar espaço, pois o c++ não tem garbage collector.

Cumps
 
Última edição:
Boa noite.

Exacto, é como fizeste no 2º exemplo. Não precisas desse método eliminar(). So podes fazer delete sobre apontadores para objectos que foram alocados dinamicamente. Nem precisas de definir um destrutor. So terias de o definir se a tua classe tivesse um atributo que fosse um pointer para um objecto alocado dinamicamente (através da palavra chave "new"). Assim, quando o objecto fosse destruído, havia a necessidade de apagar o objecto apontado por esse atributo, porque senão, ficaria um objecto perdido na memória, a ocupar espaço, pois o c++ não tem garbage collector.

Cumps

Obrigado, lá estava eu a complicar mais uma vez!

O programa está muito bem até agora não tem dado erros, só estou aqui devolta da re-ordenação do vector que está a bloquear. :S

Deixo aqui o código no caso de conseguirem ver isto mais rápido do que eu. :(

PHP:
else if ( op == "E" )
{
     cout << "\n  Eliminando Funcionario: \n";
     cout << "\n  I - " << posicaoProcura << "\n";
     Pessoas[posicaoProcura]->escrever();
     delete Pessoas[posicaoProcura];
     //Ordenando o vector
     int n;
     for( n = posicaoProcura; n <= Pessoas.size(); n++)
     {
           cout << "\n  ( FOR ) N - " << n << endl;
           Pessoas[n] = Pessoas[n+1];                            
     }
     Pessoas[n-1] = 0;
     cout << endl << "  Funciona'rio Eliminado!" << endl;
     system("PAUSE");
     op = "S";
}


Ele até aqui não dá problemas mas penso que é nesta parte que esteja o problema, continuando. .

PHP:
else if ( op == "L" )
{
    if ( Pessoas.size() == 0 )
   {
          cout << "\n Não há pessoas registadas! \n";
   }
   else
   {
    	  for (int i = 0; i < Pessoas.size(); i++) 
          {
                   Pessoas[i]->listar();
          }
    }
    cout << "\n\n";
    system("PAUSE");
}

Quando eu insiro por exemplo, 2 Funcionário, 2 Visitantes e 1 Director o programa não dá erros nenhuns, funciona perfeitamente em todas as opções.

Tenho a opção procurar onde o utilizador dá o número de identificação / número do BI e procura a determinada pessoa através desta parte do código:

PHP:
unsigned long num;
                 int posicaoProcura = -1;
                 cout << "\n  Numero de Funcionario / BI? ";fflush(stdin);
                 std::cin >> num;
                 for (int i = 0; i < Pessoas.size(); i++) 
                 {
                     if ( Pessoas[i]->getId() == num )
                     {
                          cout << "\n";
                          posicaoProcura = i;
                          break;
                     }
                 }
                 if ( posicaoProcura != -1 )
                 {
                      Pessoas[posicaoProcura]->listar();
                 }
                 else
                 {
                     cout << "\n Nao existe nenhuma pessoa com o numero ( " << num << " ) registada! ";
                 }

Entra num sub-menu de controlo da pessoa que foi procurada e tudo funciona perfeitamente e até mesmo o eliminar pessoa funciona mas depois quando volto ao menu principal, após a eliminação da pessoa vai directo a esse menu, e peço para listar as pessoas ao chegar no fim do vector bloquei-a. :(

A imagem :)

ps4.gif
 
Última edição:
Boas.
Isto é um exemplo de que o vector não é a estrutura de dados mais indicada para esse programa :)
Após eliminares uma pessoa, essa posição do vector fica a apontar para uma posição de memória que já foi libertada, e para corrigires este problema, estás a copiar os elementos posteriores uma posição para trás. Até aqui tudo bem. Mas o problema é que a ultima posição do vector fica com null (estás a iguala-a a 0). Se não o fizesses, provavelmente ficarias com 2 apontadores para o ultimo elemento. Um possível "remendo" é, após deslocares os elementos para trás, aplicares o método resize() sobre o vector para size()-1, e eliminas assim a ultima posição que não interessa já.

Código:
else if ( op == "E" )
{
     cout << "\n  Eliminando Funcionario: \n";
     cout << "\n  I - " << posicaoProcura << "\n";
     Pessoas[posicaoProcura]->escrever();
     delete Pessoas[posicaoProcura];
     for( size_t idx = posicaoProcura ; idx < Pessoas.size()-1 ; ++idx )
           Pessoas[idx] = Pessoas[idx+1];
     Pessoas.resize(Pessoas.size()-1);
     
     cout << endl << "  Funciona'rio Eliminado!" << endl;
     system("PAUSE");
     op = "S";
}

Uma solução mais elegante seria utilizares um contentor associativo. Ganhavas no tempo de pesquisa (logaritmica em vez de sequêncial) e não terias de deslocar todos os elementos para trás.

Cumps
 
Última edição:
Perfeito, funciona às mil maravilhas ;) ( Obrigado :) )

Quanto à última parte em que referes o contentor associativo eu gostava de ler sobre isso, podes dar-me algumas palavras chaves para pesquisar? É o tal map já falado antes?

Gostava também de colocar aqui outra dúvida.

Eu tenho um menu principal:

PHP:
if ( tipoMenu == "Principal" )
     {
         std::string respostaPrincipal;
         system("cls");
         cout << "\n\n MENU PRINCIPAL\n\n";
         cout << "  C - Criar Pessoa" << endl;
         cout << "  P - Procurar Pessoa" << endl;
         cout << "  L - Listar Pessoas" << endl;
         cout << "  S - Sair do Programa" << endl;
         cout << "\n  Opcao ( Ex.: V ) - ";
         fflush(stdin);
         cin >> respostaPrincipal;
         return respostaPrincipal;
     }

Que vai estar na função main() e tenho a função gerirPessoas():

PHP:
if ( tipoMenu == "GerirPessoas" )
     {
         std::string respostaPrincipal;
         system("cls");
         cout << "\n\n Gerir Pessoas\n\n";
         cout << "  F - Adicionar Funcionario" << endl;
         cout << "  V - Adicionar Visitante" << endl;
         cout << "  D - Adicionar Director" << endl;
         cout << "  S - Sair do Sub-Menu" << endl;
         cout << "\n  Opcao ( Ex.: F ) - ";
         fflush(stdin);
         cin >> respostaPrincipal;
         return respostaPrincipal;
     }

Que vai adicionar novas pessoas, apenas. O problema está em enviar um ponteiro para o vector Pessoas criado na função main() para a função gerirPessoas().

PHP:
int main()
{
    std::vector<Pessoa*> Pessoas;
    std::string op;
    
    Pessoa *p = &Pessoas;
    
    while ( op != "S" )
    {
          op = menus("Principal", "");
          if ( op == "C" ) gerirPessoa();
          //Ainda não coloquei aqui as outras opções, pois vou ter de alterar bastante o código
          if ( op == "L" ) cout << "\n\nLista de Pessoas\n\n";
    }         
    system("PAUSE");
    return EXIT_SUCCESS;
}

Este apontador que criei não está a funcionar, porque?

PHP:
void gerirPessoa(Pessoa &p)
{
    std::string op;
    
    while ( op != "S" )
    {
        op = menus("GerirPessoas", "");
        
        if ( op == "F" )
        {
             std::string nome;
             unsigned long num;
             cout << "\n  Inserindo novo Funcionário \n";
             std::cout << "\n  Insira o nome: "; fflush(stdin);
             getline ( cin, nome );
             std::cout << "  Insira o num: "; fflush(stdin);
             std::cin >> num;
             
             Pessoa* f = new Funcionario(nome, num);
             p.push_back(f);

Nesta parte dá erro:

'class Pessoa' has no member named 'push_back'

Dá também erro na linha:

Pessoa *p = &Pessoas;

cannot convert `std::vector<Pessoa*, std::allocator<Pessoa*> >*' to `Pessoa*' in initialization

Devo ter qualquer coisa mal :S

Cumprimentos,
Nelson Ferreira
 
Última edição:
PHP:
int main()
{
    std::vector<Pessoa*> Pessoas;
    std::string op;
    
    while ( op != "S" )
    {
          op = menus("Principal", "");
          if ( op == "C" ) gerirPessoa(&Pessoas);

PHP:
void gerirPessoa(Pessoa* Pessoas)
{
    //std::vector<Pessoa*> Pessoas;
    std::string op;
    
    while ( op != "S" )
    {
        op = menus("GerirPessoas", "");
        
        if ( op == "F" )
        {
             std::string nome;
             unsigned long num;
             cout << "\n  Inserindo novo Funcionário \n";
             std::cout << "\n  Insira o nome: "; fflush(stdin);
             getline ( cin, nome );
             std::cout << "  Insira o num: "; fflush(stdin);
             std::cin >> num;
             
             Pessoa* f = new Funcionario(nome, num);

Tentei agora também por referência e não consigo, será impossivel?
 
Boa noite.

É normal que o compilador se queixe. Pela assinatura da tua função:

Código:
void gerirPessoa(Pessoa* Pessoas)
{
   ....
}
A função espera como parametro um pointer para objectos do tipo pessoa e tu estás a passar-lhe um vector de pessoas. Altera a assinatura função para:

Código:
void gerirPessoa(std::vector<Pessoa*> &p)
{
   ....
}

Assim já podes manipular o vector de pessoas dentro da função (não te esqueças dessa passagem por referência).

Quanto ao contentor associativo, sim, é o map que vem na STL.

Cumps
 
Boa Tarde,

ontem estive a tratar do programa e está tudo a andar muito bem, funciona perfeitamente com o vector. Estive também a fazer a parte em que gravo num ficheiro a info quando termino o programa e lei-o do a info que reabro o programa. .

. .pois estava tudo bem até agora, estou a tentar implementar o contentor associativo map e está complicado de conseguir prosseguir, tenho um problema ao inserir um novo Funcionario ( por ex. ) no map.

Aqui fica a minha ideia:

PHP:
int main()
{
    //std::vector<Pessoa*> Pessoas;
    map<Pessoa, string> mapDePessoas;

Tenho este map de Pessoas, em que vou guardar o ponteiro para a pessoa e o tipo de Pessoa ( Funcionario, Visitante ou Director ), isto vai-me facilitar quando guardar a informação no ficheiro e para a carregar também.

Até aqui parece estar tudo bem. . Passo o map para outra função:

PHP:
while ( op != "S" )
    {
          op = menus("Principal", "");
          if ( op == "C" ) gerirPessoa(/*Pessoas*/ mapDePessoas);

Recebo o map e crio um novo funcionário:

PHP:
void gerirPessoa(map<Pessoa, string> mapDePessoas)
{
    std::string op;
    
    while ( op != "S" )
    {
        op = menus("GerirPessoas", "");
        
        if ( op == "F" )
        {
             std::string nome;
             unsigned long num;
             int i = 0;
             cout << "\n  Inserindo novo Funcionário \n";
             std::cout << "\n  Insira o nome: "; fflush(stdin);
             getline ( cin, nome );
             std::cout << "  Insira o num: "; fflush(stdin);
             std::cin >> num;
             
             Pessoa* f = new Funcionario(nome, num);
             mapDePessoas.insert(f, "Funcionario");

É neste última linha que surge o problema/erro :

In instantiation of `std:: pair<const Pessoa, std::string>':
instantiated from `std::_Rb_tree_node<std:: pair<const Pessoa, std::string> >'
instantiated from here
cannot declare field `std:: pair<const Pessoa, std:: string>::first' to be of type `const Pessoa'

É verdade que vi outra maneira de fazer a mesma coisa mas pareceu-me mais complexo e também não funcionou:

PHP:
//Definindo
typedef map<Pessoa, string> mapType;
typedef mapType::value_type valuePairType;

main()
{
   mapType mapDePessoas;
   mapType::iterator it;  //iterator

   //Inserindo
   mapDePessoas.insert(valuePairType(f,"Funcionario"));
}

Mais uma vez apelo pela vossa sabedoria, que a minha é muito pouca :(
 
Última edição:
Boas.
Estas a criar o map de forma errada. Estás a associar uma string a um apontador para Pessoa, quando quanto muito, deveria ser o contrário. O map é constituido por pares chave/valor associado, onde a chave é utilizada para pesquisares valores no map. Para utilizar o map deves escolher um atributo de Pessoa cujo valor seja unico para cada instância, como por exemplo o numero do bi ou o número de funcionário, já que varias pessoas podem ter o mesmo nome. Se queres associar ao estatuto da pessoa, terás de optar por um multimap pois um map não admite chaves repetidas. No teu lugar optava pelo bi/numFuncionario, ja que tens, suponho eu, um método getId em pessoa como ja tinhamos discutido.
Para auxiliar a pesquisa no map, deverias adicionar um método estatuto ou getEstatuto, virtual puro em Pessoa.

pessoa.h
Código:
virtual const char* estatuto()=0;

E redifines em todas as classes:

visitante.cpp
Código:
const char* visitante::estatuto() const
{
    return "Visitante";
}

Director.cpp
Código:
const char* Director::estatuto() const
{
    return "Director";
}
etc....

Utilização do map
Código:
// supondo que tens o id da pessoa numa variavel de nome id

std::map<int,Pessoa*> pessoas; //cria um map

std::map<int,Pessoa*>::const_iterator search = pessoas.find(id); //verifica se ja existe uma pessoa com esse id

if (search != pessoas.end())
{
   std::cout << "Já existe uma pessoa com esse id:\n";
   std::cout << (*search)->getId() << " - " << (*search)->getName() << " - " << (*search)->estatuto << std::endl
}

else
{
  Pessoa* p = new Director("Manuel", 1233,.....); //cria a instancia de pessoa
  pessoas.insert(std::make_pair(p->getId(), p)); //insere o pointer no map
  std::cout << "Adicionado" << std::endl;
}

//Para mostrares todos as pessoas

for (std::map<int,Pessoa>::const_iterator i= pessoas.begin() ; i!=pessoas.end() ; ++i)
     std::cout << (*i)->getId() << " - " << (*i)->getName() << " - " << (*i)->estatuto << std::endl;


//Para mostrares só os visitantes

for (std::map<int,Pessoa>::const_iterator i= pessoas.begin() ; i!=pessoas.end() ; ++i)
     if ((*i)->estatuto == "Visitante")
           std::cout << (*i)->getId() << " - " << (*i)->getName() << " - " << (*i)->estatuto << std::endl;

Fica bem.
 
Última edição:
Obrigado pelo exemplo. :)

Mas comigo não está a funcionar, já tentei alterar estive até a ver o problema entre o Funcionário e o Director, por causa do estatuto mas não era disso. >(

Adaptei o teu método ao meu código:

PHP:
void gerirPessoa(std::map<int, Pessoa*> mapaDePessoas)
{
    std::string op;
    while ( op != "S" )
    {
        op = menus("GerirPessoas", "");
        
        if ( op == "F" )
        {
             std::string nome;
             unsigned long num;
             int i = 0;
             Pessoa* f;
             
             cout << "\n  Inserindo novo Funcionário \n";
             std::cout << "\n  Insira o nome: "; fflush(stdin);
             getline ( cin, nome );
             std::cout << "  Insira o num: "; fflush(stdin);
             std::cin >> num;
             
             std::map<int,Pessoa*>::const_iterator search = mapaDePessoas.find(num); //verifica se ja existe uma pessoa com esse id
             
             if ( search != mapaDePessoas.end())
             {
                 std::cout << "Já existe uma pessoa com esse id:\n";
                 //std::cout << (*search)->getId() << " - " << (*search)->getName() << " - " << (*search)->estatuto() << std::endl;
             }
             else
             {
                 f = new Funcionario(nome, num); //cria a instancia de funcionario
                 mapaDePessoas.insert(std::make_pair(f->getId(), f)); //insere o pointer no map

Erro -> cannot allocate an object of type `Funcionario'; because the following virtual functions are abstract: virtual const char* Pessoa::estatuto() .

Pessoa.h

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

No pessoa.cpp não coloquei nada pois não é necessário, tal como não coloquei no getId(), certo?
 
Oops.. desculpa.. não me lembrei que Director deriva de Funcionario. Surge esse erro porque o método estatuto tem de estar também redefinido em Funcionario, porque senão a classe é considerada abstracta. Precisas de redefinir em Funcionario, mas como virtual não puro para poderes fazer chamadas polimorficas a esse método nos tipos que derivam de Funcionario.

Funcionario.cpp

Código:
virtual const char* Funcionario::estatuto()
{
    return "Funcionario";
}

Director.cpp

Código:
const char* Director::estatuto()
{
    return "Director";
}

O getId() é virtual puro em Pessoa e tem de ser redefinido em Visitante e em Funcionario. Não precisa em Director porque herda a implementação de Funcionario.

Outra coisa, passa o map por referência á função gerirPessoa

Código:
void gerirPessoa(std::map<int, Pessoa*> &mapaDePessoas)

Fica bem
 
Última edição:
Bem não consegui resolver dessa maneira mas penso que acaba por ser a mesma coisa, aqui fica:

PHP:
//Pessoa.h
virtual const char* estatuto()=0;

PHP:
//Funcionario.h
virtual const char* estatuto();

//Funcionario.cpp
const char* Funcionario::estatuto()
{
    return "Funcionario";
}

PHP:
//Director.h
virtual const char* estatuto();

//Director.cpp
const char* Director::estatuto()
{
    return "Director";
}

De qualquer maneira está a correr e faz tudo como deve ser ;)

O meu problema agora é o iterator não está a funcionar como deve ser.

PHP:
for ( map<int,Pessoa*>::const_iterator i = mapaDePessoas.begin() ; i != mapaDePessoas.end() ; ++i )
{    
     cout << (*i)->getId() << " - " << (*i)->getName() << " - " << (*i)->estatuto << endl;
}

Erro -> base operand of `->' has non-pointer type `const std:: pair<const int, Pessoa*>'

Uma outra coisa, eu estou a utilizar a seguinte expressão:

PHP:
if ( mapaDePessoas.size() == 0 )
{
     cout << "\n Não há pessoas registadas! \n";
}

Também é válido para um map? Sabes onde poderei ler mais sobre estas propriedades?
 
Última edição:
Penso que o map não tem um método size(). Quanto ao outro erro, parece que afinal o iterador devolve um pointer para o par chave/valor associado :P Assim sendo o que queres é o segundo elemento do par.

Código:
for ( map<int,Pessoa*>::const_iterator i = mapaDePessoas.begin() ; i != mapaDePessoas.end() ; ++i )
{    
     cout << i->second->getId() << " - " << i->second->getName() << " - " << i->second->estatuto << endl;
}
 
Penso que o map não tem um método size().

No meu projecto está a funcionar correctamente :)

Quando o map se encontra vazio, logo ao inciar o programa por exemplo, ele entra no ciclo onde tenho isso:

PHP:
if ( mapaDePessoas.size() == 0 )
{
     cout << "\n Não há pessoas registadas! \n";
}
else
{
     . .
}

Quanto ao outro erro, parece que afinal o iterador devolve um pointer para o par chave/valor associado

Não percebi bem o conceito de iterador e por isso esta parte passou-me um bocado ao lado :(
Eu andei a ler sobre iterador mas são pouco claros ( ou eu muito burro! ), ele funciona como um apontador para um determinado lugar do map?

Obrigado pela ajuda :x2:

Já avancei mais um pouco, mas encontro um problema que já tinha reparado quando aconteceu o erro anterior.

Eu fiz um if() para cada tipo de estatuto para poder adicionar nos diferentes estatutos, as diferentes propriedades/metodos. Tenho isto:

PHP:
// Mostrar todas as pessoas
                   cout << "\n  Listagem de Pessoas \n\n";
                   for ( map<int,Pessoa*>::const_iterator i = mapaDePessoas.begin() ; i != mapaDePessoas.end() ; ++i )
                   {
                       if ( i->second->estatuto() == "Funcionario" )
                       {
                            cout << "  " << i->second->estatuto() << " - " << i->second->getId() << endl;
                       }
                       else if ( i->second->estatuto() == "Visitante" )
                       {
                            cout << "  " << i->second->estatuto() << " - " << i->second->getId() << endl;
                       }
                       else if ( i->second->estatuto() == "Director" )
                       {
                            cout << "  " << i->second->estatuto() << " - " << i->second->getId() << " - " << i->second->obtemDepartamento() << endl;
                       }
                   }

E o erro que dá, tem lógica "'class Pessoa' has no member named 'obtemDepartamento'" e sendo assim como tenho acesso a metodos particulares de uma determinada class?
 
Última edição:
Já avancei com o projecto e finalmente faz o pedido no enunciado, tirando o problema do tópico anterior, agradeço a todos os que que me ajudaram mais uma vez :x2: . Basta o esclarecimento que pedi no tópico anterior para conseguir fazer o carregamento correcto dos dados guardados no ficheiro.

Gostava a penas de receber a vossa opinião relativamente à maneira de como fiz essa leitura, aqui fica o código:

Guardar Dados

PHP:
void guardaDados(map<int,Pessoa*> &mapaDePessoas)
{
     ofstream myfile;
     const char* fname = "fileout.txt";
     myfile.open (fname);
     if ( !myfile )
     {
        cout << "  File: " << fname << " not open";
     }
     else
     {
         for ( map<int,Pessoa*>::const_iterator i = mapaDePessoas.begin() ; i != mapaDePessoas.end() ; ++i )
         {
             if ( i->second->estatuto() == "Funcionario" )
             {
                  myfile << i->second->estatuto() << " - " << i->second->getId() << " - " << i->second->obtemNome() << " - \n";
             }
             else if ( i->second->estatuto() == "Visitante" )
             {
                  myfile << i->second->estatuto() << " - " << i->second->getId() << " - " << i->second->obtemNome() << " - \n";
             }
             else if ( i->second->estatuto() == "Director" )
             {
                  myfile << i->second->estatuto() << " - " << i->second->getId() << " - " << i->second->obtemNome() << " - \n";
             }
         }
     }
     myfile.close();
}

Nesta parte falta-me adicionar o departamento aos Directores, o tal problema do tópico anterior.

Carregar Dados

PHP:
void carregaDados(map<int,Pessoa*> &mapaDePessoas)
{
     const char* fname = "fileout.txt";
     ifstream myfile(fname);
     if ( !myfile )
     {
        cout << "  File: " << fname << " not open";
     }
     else
     {
         while ( !myfile.eof() )
         {
               string leitura;
               myfile >> leitura;
               
               cout << "\n  TESTANDO - " << leitura << endl;

Parte inicial da Função. . Em baixo a parte relativa a funcionários, vou só colocar essa pois o método de como carrego os dados dos outros ( Visitante e Director ) pouco difere deste. Aqui fica o código. .

PHP:
if ( leitura == "Funcionario" )
{
       string idString, Nome;
       int contador = 0; // Faz a contagem dos '-' existentes em cada linha
       int id = 0;
                    
       myfile >> leitura;
       while ( contador != 3 )
       {
              if ( leitura != "-" )
              {
                    if ( contador == 1 )
                    {
                           idString = leitura;
                           char le[5];
                           myfile >> leitura;
                           for ( int cont = 0; cont <= idString.size() ; cont++ )
                           {
                                   le[cont] = idString[cont]; // Passagem da string para char
                           }
                           id = atoi(le); // Converte char para inteiro
                    }
                    else if ( contador == 2 )
                    {
                           Nome = leitura;
                           myfile >> leitura;
                           while ( leitura != "-" )
                           {
                                  Nome = Nome + " " + leitura;
                                  myfile >> leitura;
                           }
                           Pessoa* f = new Funcionario(Nome, id); //cria uma instância de funcionario
                           mapaDePessoas.insert(make_pair(f->getId(), f)); //insere o ponteiro no mapa de pessoas
                           cout << "\n  Nome: " << Nome << " ID: " << id << endl;
                           break;
                    }
             }
             if ( leitura == "-" )
             {
                    contador++;
                    if ( contador != 3 )
                    {
                           myfile >> leitura;
                    }
             }
     }
}

PHP:
         }
     }
     system("PAUSE");
     myfile.close();
}

O ficheiro onde estão os dados encontra-se assim. .

Funcionario - 1 - Manuel Jaquim -
Funcionario - 2 - Nelson F2 -
Director - 3 - Nelson D -
Visitante - 4 - Nelson V -
Visitante - 5 - Nelson V2 -

Que acham? :)

*Eu sei que está um bocado estranho mas não consegui obter o "\n", seria mais facil assim. :(
 
Última edição:
Boas :),

espero que o Natal tenha sido bom.

Cá ando eu devolta do projecto novamente e com alguns problemas ainda por resolver, espero que possam ajudar.

A situação é a seguinte; estou com problemas no que toca a obter o departamento do Director, visto que na classe Pessoa esse método não está definido ele não devolve o departamento.

Tentei fazer usando o polimorfismo e o virtual puto:

PHP:
//Pessoa.h

virtual std::string obtemDepartamento()=0;

PHP:
//Funcionario.h

virtual std::string obtemDepartamento();

Mas se o fizer desta maneira terei que fazer a mesma coisa para a classe Visitante que também deriva da classe Pessoa e ai surgem problemas, visto que não existe nenhum departamento para os Visitantes. O código seria assim:

PHP:
//Visitante.h

virtual std::string obtemDepartamento();

Como poderei solucionar este problema? Na listagem das pessoas coloquei o seguinte código:

PHP:
cout << "\n  Listagem de Pessoas\n\n";
for ( map<int,Pessoa*>::const_iterator i = mapaDePessoas.begin() ; i != mapaDePessoas.end() ; ++i )
{
      if ( i->second->estatuto() == "Director" )
            cout << "  " << i->second->estatuto() << " - " << i->second->getId() << " - " << i->second->obtemNome() << " - " << i->second->obtemDepartamento() << endl;
      else
            cout << "  " << i->second->estatuto() << " - " << i->second->getId() << " - " << i->second->obtemNome() << endl;
}

Mas isto dá erro quando xega a um determinado funcionário.

Solucionei o problema para a parte da listagem, ficou assim:

PHP:
cout << "  " << i->second->estatuto() << " - ";
i->second->listar();
cout << endl;

Com o método listar consigo toda a informação necessário. Agora tentei fazer da mesma maneira para a função onde guardo os dados no ficheiro mas complicou um bocado, vou tentar criar um método para ver se consigo solucionar o problema, o código está assim:

PHP:
ofstream myfile;
const char* fname = "fileout.txt";
myfile.open (fname);
if ( !myfile )
{
    cout << "  O Ficheiro: " << fname << " não abriu";
}
else
{
    for ( map<int,Pessoa*>::const_iterator i = mapaDePessoas.begin() ; i != mapaDePessoas.end() ; ++i )
    {
        myfile << i->second->estatuto() << " - ";
        myfile << i->second->listar();
        myfile << endl;
    }
}
myfile.close();

Obrigado pela ajuda.

Cumprimentos,
Nelson Ferreira
 
Última edição:
Back
Topo