I am trying to make a priority queue with a specific type class 'alumnos'.

I create 3 new classes (new, medium, old) who inherit from it.

Then I insert the classe into de queue. I would like to use polymorphism when extracting to use the correct function 'verificarEdad' but gives the error:

cola.cpp: 66: error: invalid initialization of the reference rate 'alumnos&' from an expression of type' const alumnos'

The code:

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

class alumnos{
	public:
		string nombre;
		int edad;
		
		alumnos( string nombre, int edad ){
			this -> nombre = nombre;
			this -> edad = edad;
		};
		virtual void verificarEdad(){
			cout << "alumno" << endl;
		};
	
};

class nuevo : public alumnos{
	public:
	nuevo( string nombre, int edad ) : alumnos(nombre,edad){};
	
	void verificarEdad(){
		if (edad < 20)
			cout << "Nuevo" << endl;
	};
};

class medio : public alumnos{
	public:
	medio( string nombre, int edad ) : alumnos (nombre, edad){};
	
	void verificarEdad(){
		if (edad > 20 && edad < 30)
			cout << "Medio" << endl;
	};
};

class viejo : public alumnos{
	public:
	viejo( string nombre, int edad ) : alumnos (nombre, edad){};
	
	void verificarEdad(){
		if (edad > 30)
			cout << "Viejo" << endl;
	};
};

bool operator > (alumnos alumno1, alumnos alumno2)
{
	return alumno1.edad > alumno2.edad;
}

int main ()
{
 	priority_queue<alumnos, vector<alumnos>, greater<vector<alumnos>::value_type> > mypq;
	
	mypq.push(nuevo("Helder", 25));
	mypq.push(nuevo("Pepe", 18));
	mypq.push(viejo("Pepito", 31));
	mypq.push(medio("Juan", 21));

	alumnos &al = mypq.top();

	while (!mypq.empty()){
		al.verificarEdad();
		cout << "mypq.top() is now " << al.nombre << endl;
		mypq.pop();
	}

	return 0;
}

How can I solve my problem?

Thanks.

Recommended Answers

All 9 Replies

Please use code tags in future to make code more readable.

The error is due to top() returning a temporary reference, and you're trying to reference it as non-constant. You could use a const alumnos &al, and make sure all member functions called on al are const (inspector functions - that don't change anything in the class).

Or, The easiest way is to use a const_cast in the reference assignment:

alumnos &al = const_cast<alumnos &>(mypq.top());

Thanks.

I change the instruction to:

alumnos &al = const_cast<alumnos &>(mypq.top());

But when I try to do al.verificarEdad() the polymorphism dosen´t work. Always call the class alumnos (print alumnos).

Wich changes in my program I have to made to use the priorityqueue and polymorphism?

I don't know why your compiler gives the error (what's a compiler are you using? ). My VC++ 2008 compiles your source OK. In actual fact std::priority_queue::top() returns non-constant reference, so your original stmt#66 is OK.

Another problem: where is desired polymorphism? Alas, when you declare priority_queue<alumnos>, only alumnos part of successors will be pushed in the container! It's known as a slicing. STL containers contain objects of one and only one type.

To use polymorphism, declare priority_queue<alumnos*> and push pointers to objects into the queue. Naturally, you must correct your code properly after that, especially initialization of the queue part, for example:

mypq.push(new nuevo("Helder", 25));
mypq.push(new nuevo("Pepe", 18));
mypq.push(new viejo("Pepito", 31));
mypq.push(new medio("Juan", 21));

Don't forget to add deallocation code: now the priority_queue destructor frees only pointers but not pointed objects.

Oh, once more remarks:
1. It's a slightly strange code:

class nuevo : public alumnos {
public:
    nuevo( string nombre, int edad ) : alumnos(nombre,edad){};
    void verificarEdad() {
        if (edad < 20)
            cout << "Nuevo" << endl;
    }

You write nuevo::verificarEdad() member function. It KNOWS that it's a class nuevo object! So why if (...)? Want to use polymorphism? Use it! No need in special data discriminator values. For example, in your class hierarchy you can write (legally)

mypq.push(new nuevo("Helder", 25000000)); // Where is error exception?

If it's not a desired behaviour, redesign your object model.
2. It's not C++ requirement but common practice is to start user-defined class names from the capitals, for example:

class Nuevo: public Alumnos {
...

Thanks for your help.

I know the name of the classes start's with capital, but thanks for the observation.
The if inside the object's it's only to print the message, naturally I could erase the if.

After I change the statment:

priority_queue<Alumnos*, vector<Alumnos*>, greater<vector<Alumnos*>::value_type> > mypq;

plus the changes:

mypq.push(new Medio("Helder", 25));
mypq.push(new Nuevo("Pepe", 18));
mypq.push(new Viejo("Pepito", 31));
mypq.push(new Medio("Juan", 21));

Alumnos *al = const_cast<Alumnos *>(mypq.top());

my program is working.

This is a very simple program to learn how to use polimorphism and the priorityqueue.

I have a final question in this container I can do interations?

For example search an object inside the queue.

Of course, you can do iterations. Don't forget: now you have pointers (not objects) in the container - that's all. I think no need in const_cast now...
Good luck!

You was right. I don't need the cast.

When I try to access to the priority queue the only valid methods are: top(), empty, size(), pop() and push().

You said I can interact, but how?

It's possible but it's not so easy as I said in my previous post.
The point is that std::priority_queue has not open interface to iterate its underlying container (std::vector by default or std:deque). However the C++ Standard leaves a loophole: underlying container is a protected member c. It's possible to access it from std::priority_queu derived class.
Look at this improvisation:

/// Something with type and name
class Entity
{
public:
    Entity(const char* ptype, const char* pname):
      stype(ptype?ptype:"unknown"), 
      sname(pname?pname:"unknown")
    {}
    virtual ~Entity() {}
    const char* type() const { return stype.c_str(); }
    const char* name() const { return sname.c_str(); }
private:
    string stype;
    string sname;
};
/// Generic abstract class
class Aircraft: public Entity
{
public:
    virtual ~Aircraft() {}
    virtual int bombs() const = 0;
protected:
    Aircraft():Entity(0,0) {}
    Aircraft(const char* ptype, const char* pname):
    Entity(ptype,pname)
    {}
};

class Fighter: public Aircraft
{
public:
    Fighter(const char* name, int drops = 0):
      Aircraft("fighter",name), pylons(drops)
    {}
    const char* type() const { return "fighter"; }
    int bombs() const { return pylons; }
protected:
    int pylons;
};

class Bomber: public Aircraft
{
public:
    Bomber(const char* name, double load):
      Aircraft("bomber",name), bombload(load)
    {}
      int bombs() const 
      { 
          return static_cast<int>(bombload/1000.0); 
      }
protected:
    double bombload;
};

class Liner: public Aircraft
{
public:
    explicit Liner(const char* name): Aircraft("liner",name)
    {}
    int bombs() const { return 0; }
};
/** It's not a smart pointer.
 *  We need this type to define a proper operator>()
 *  for priority_queue (priority is bombload)...
 */
class Apointer
{
public:
    Apointer():ptr(&dummy) {}
    //~Apointer() { if (ptr != &dummy) delete ptr; }
    Apointer(Aircraft* p):ptr(p?p:&dummy) {}
    operator Aircraft*() { return ptr; }
    Aircraft* getPtr() { return ptr; }
    Aircraft* operator->() { return ptr; }
    const Aircraft* operator->() const
    {
        return ptr;
    }
    bool operator >(const Apointer& p)
    {
        return ptr->bombs() > p->bombs();
    }
private:
    Aircraft* ptr;
    /// Optional: we are trying to avoid nullptr...
    static Liner dummy;
};

bool operator >(const Aircraft& a1, const Aircraft& a2)
{
    return a1.bombs() > a2.bombs();
}
/// For priority_queue.
bool operator >(const Apointer& pa1, const Apointer& pa2)
{
    return pa1->bombs() > pa2->bombs();
}

bool operator <(const Apointer& pa1, const Apointer& pa2)
{
    return pa1->bombs() < pa2->bombs();
}
// Use typedefs when picking with STL stuff...
typedef priority_queue<Apointer> Airpark;

typedef priority_queue<Apointer>::container_type::const_iterator Iter;
/// A trick: we want to access underlying container.
struct Fleet: public Airpark
{
    Fleet():Airpark() {}
    const Iter begin() const { return c.begin(); }
    const Iter end() const { return c.end(); }
};

typedef Fleet::container_type::const_iterator Fiter;

/// Place it in implementation cpp file...
Liner Apointer::dummy(0);
/// Test routine.
void TestAir()
{
    Fleet park;

    park.push(new Fighter("F-15C",8));
    park.push(new Fighter("F-86F",2));
    park.push(new Bomber( "B-52G",50000.0));
    park.push(new Liner(  "B.777"));

    cout << "park.size: " << park.size() << '\n';

    cout << "\nUnderlaying container iteration:\n\n";
    for (Fiter p = park.begin(); p != park.end(); ++p)
        cout << (*p)->name() << '\n';
    cout << "\nPriority queue unloading:\n" << endl;
    while (!park.empty())
    {
        Apointer p = park.top();
        cout << p->name() << ' ' << p->type() << ' '
            << p->bombs() << " bombs load" << '\n';
        park.pop();
        delete p;
    }
    cout << "\nDone" << endl;
}
/* Output:
park.size: 4

Underlaying container iteration:

B-52G
F-86F
F-15C
B777

Priority queue unloading:

B-52G bomber 50 bombs load
F-15C fighter 8 bombs load
F-86F fighter 2 bombs load
B.777 liner 0 bombs load

Done
*/

May be it helps you to modify your code. Pay attention: iteration sequence is not ordered by priority!

Moral: a priority_queue data structure is not adjusted for element by element iterations. The priority name part has a priority over queue part. It's a very specialized container with a heavy truncated interface.

If you want to iterate it, better define your own class (it's not so easy too). Probably, the best solution is to collect all these pointers to objects in a separate container (for example, in std::vector) to iterate it. Add same pointers in priority_queue if you wish. It's a simple and effective solution.

My doubts for now are solved.

Thanks for the help.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.