I have a problem in polymorphism with list STL

Please help me with a problem to solutions the polymorphism in this case...

I have iterator of class Cliente and the class ClienteJuridico and ClienteNatural inherit of super class Cliente the method MostrarTipo().

Class Cliente
1
2
3
virtual void MostrarTipo(){
  cout << "Tipo no definido";
}


Class ClienteJuridico
1
2
3
void MostrarTipo(){
  cout << "Persona Natural";
}

Class ClienteNatural
1
2
3
void MostrarTipo(){
  cout << "Persona Juridica";
}


... however, in the main function I implement class list and use the follow iterator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 if(!lstClientes.empty()){
     list<Cliente>::iterator ptroCliente;
     ptroCliente = lstClientes.begin();
     system("cls"); // EN WINDOWS
     cout << "------------------------------------------------------------------------------\n";
     cout << "ID\t";cout << "NOMBRE\t\t";cout << "TIPO CLIENTE\n";
     cout << "------------------------------------------------------------------------------\n";
     while(ptroCliente != lstClientes.end()){
             cout << ptroCliente->geIdCliente();cout<< "\t";
             ptroCliente->MostrarNombre();cout<< " ";ptroCliente->MostrarApellido();
             cout<< "\t";
             ptroCliente->MostrarTipoCliente();
             cout << endl;
             ptroCliente++;
      }
}else{
      cout << endl << "No hay Clientes!" << endl;
}


But de result is "Tipo no definido..."

Please help me ! ...

Last edited on
As far as I know, in your case lstClientes must contain pointers, because std::list stores a copy of the object.
In your case, lstClientes contains objects of type Cliente, even if you push_back ClienteJuridico or ClienteNatural.
Changing lstClientes to list<Cliente*> will solve your problem.
Obviously, be careful of memory leaks.
Maybe you would use manager pointers: see http://www.cplusplus.com/reference/memory/
You can also try to make it a virtual member.
Remember to make the destructor virtual, too, if you choose this path.
Yes EssGeEich, i already tried to make the virtual method of super class Clientes.
1
2
3
virtual void MostrarTipo(){
  cout << "Tipo no definido";
}

But the problem is how to say fcantoro, lstCliente store a copy of the object. Then i probed the following code...

1
2
3
4
5
6
7
    Cliente *cte2,*cte3;
    cte2 = new ClientePersonaJuridica(1,"Asociados","","123456789");
    Fecha fn(8,2,1988);
    cte3 = new ClientePersonaNatural(1,"Ricardo","Carranza","123456",fn);
    cte2->MostrarTipoCliente();
    cout << endl;
    cte3->MostrarTipoCliente();


And the answer is correct...
1
2
Persona Juridica
Persona Natural


But when i using a iterator of class list lstClientes, the answer is ...

Tipo no definido

:-/
Last edited on
Here's an example to serve the point fcantoro made:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <list>

class Cliente
{
public:
    virtual void MostrarTipo()
    {
        std::cout << "Tipo no definido";
    }
};

class ClienteJuridico : public Cliente
{
public:
    virtual void MostrarTipo()
    {
        std::cout << "Persona Juridica";
    }
};

class ClienteNatural : public Cliente
{
public:
    virtual void MostrarTipo()
    {
        std::cout << "Persona Natural";
    }
};

int main(int argc, char* argv[])
{
    std::list<Cliente> cList;
    cList.emplace_back(ClienteJuridico());
    cList.emplace_back(ClienteNatural());

    std::cout << "Using list of objects\n";
    for(std::list<Cliente>::iterator it = cList.begin();
                                     it != cList.end();
                                     ++it)
    {
        (*it).MostrarTipo();
        std::cout << std::endl;
    }


    std::list<Cliente*> cPtrList;
    cPtrList.emplace_back(new ClienteJuridico());
    cPtrList.emplace_back(new ClienteNatural());
    std::cout << "\nUsing list of pointers to objects\n";
    for(std::list<Cliente*>::iterator it = cPtrList.begin();
                                     it != cPtrList.end();
                                     ++it)
    {
        (*it)->MostrarTipo();
        std::cout << std::endl;
    }
    return 0;
}
You must make the base's class a virtual method.
About copying, you should store pointers instead of objects (if you are allowed to).
This is kind of what you should have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class BaseClient {
public:
    virtual void Display() =0;
    virtual ~BaseClient() {} // Important!
    // If you split header/source, put the (empty) body in the source file.
};

class JurClient : public BaseClient {
public:
    virtual void Display() { std::cout << "Jur. Client"; }
};

class NatClient : public BaseClient {
public:
    virtual void Display() { std::cout << "Nat. Client"; }
};


And the rest of the code should be like this:

1
2
3
4
5
6
7
8
9
10
11
std::list<std::unique_ptr<BaseClient>> clients;
clients.push_back(std::unique_ptr<BaseClient>(new JurClient()));
clients.push_back(std::unique_ptr<BaseClient>(new NatClient()));

unsigned int ClientID = 0;
for(auto const& it : clients)
{
    std::cout << "Client nr. " << ++ClientID << " is a ";
    it->Display();
    std::cout << std::endl;
}


Some of the code uses C++11 features (such as std::unique_ptr and range-for.

If you really want to follow a different approach, store all the infos in a single class as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
enum ClientType {
    CT_NATURAL = 0, // = 0 is important
    CT_JURIDICA,

    CT_AMOUNT // must be the last one, tells us how many types are there
};
class Client {
    ClientType m_ClientType;
public:
    Client(ClientType t = CT_NATURAL) // If no ClientType is provided, use CT_NATURAL.
        : m_ClientType(t) {}
    void Display() const { // Note: Marked as const, since it doesn't modify Client itself.
        // static: initialized once
        // const: does not change
        static const std::string TypeToName[CT_AMOUNT] = {
            "Persona Natural",
            "Persona Juridica"
        };
        if(m_ClientType < 0 || m_ClientType >= CT_AMOUNT)
            std::cout << "Tipo no definido";
        else
            std::cout << TypeToName[m_ClientType];
    }
};


And use as follows:
1
2
3
4
5
6
7
8
9
10
11
12
std::list<Client> clients;
clients.push_back(Client(CT_NATURAL));
clients.push_back(Client(CT_JURIDICA));
clients.push_back(Client(ClientType(42))); // client type of id 42? it does not exist, and will print Tipo no definido.

unsigned int ClientID = 0;
for(auto const& it : clients)
{
    std::cout << "Client nr. " << ++ClientID << " is a ";
    it.Display();
    std::cout << std::endl;
}
Heeeeey !!! yes ! this is a solution, thaks booradley60 and fcantoro ! and parnerts ! Here's an image with the result:

https://www.dropbox.com/s/rfln4q9w3p547du/cplusplus_cliente.png?dl=0

Thanks for your time ! :-)
Last edited on
Topic archived. No new replies allowed.