tags:

views:

185

answers:

8

LessonInterface

class ILesson
{
    public:
        virtual void PrintLessonName() = 0;
        virtual ~ILesson() {}
};

stl container

typedef list<ILesson> TLessonList;

calling code

for (TLessonList::const_iterator i = lessons.begin(); i != lessons.end(); i++)
    {
        i->PrintLessonName();
    }

The error:

Description Resource Path Location Type passing ‘const ILesson’ as ‘this’ argument of ‘virtual void ILesson::PrintLessonName()’ discards qualifiers

+6  A: 

You can't "put" objects of a class that has pure virtual functions(because you can't instantiate it). Maybe you mean:

// store a pointer which points to a child actually.
typedef list<ILesson*> TLessonList;


OK, as others pointed out, you have to make PrintLessonName a const member function. I would add that there is another small pitfall here. PrintLessonName must be const in both the base and the derived classes, otherwise they will not have the same signature:

class ILesson
{
public:
    virtual void PrintLessonName() const = 0;
    virtual ~ILesson() {}
};


class SomeLesson : public ILesson
{
public:
    // const is mandatory in the child
    virtual void PrintLessonName() const
    {
     //
    }
    virtual ~SomeLesson() {}
};

To be honest, I find Jerry Coffin's answer helpful for redesigning the printing functionality.

AraK
While this is true, it the error message jack has pasted isn't due to this error.
sbi
tried and Error is :Description Resource Path Location Typerequest for member ‘PrintLessonName’ in ‘* i.std::_List_const_iterator<_Tp>::operator-> [with _Tp = ILesson*]()’, which is of non-class type ‘ILesson* const’
jack london
I didn't observe the const issue, my eyes first fell on `typedef list<ILesson> TLessonList;`. Anyway, he has to fix this one also.
AraK
@jack: try `(*i)->PrintLessonName()` instead. Since you are using pointers now, dereferencing the iterator yields a pointer instead of an object instance.
D.Shawley
+1  A: 

You call a non-const method for a const object refered through a reference to const object.

Anyways:

I'm 100% sure you need to have a list of pointers:

typedef list<ILesson*> TLessonList;

in order to take advantage of polymorphism.

Having a list of values of ILesson is not possible, since ILesson is an abstract class.

Don't forget to delete the objects in the list of pointers, to avoid memory leaks.

Cătălin Pitiș
+3  A: 

Use iterator instead of const_iterator or make PrintLessonName() const function:

virtual void PrintLessonName() const = 0
Shay Erlichmen
Ugh. What about making the function `const` instead? It's not like we'd expect printing to change the printed object.
sbi
Read my answer "OR MAKE THE THE FUNCTION CONST"
Shay Erlichmen
Ah, my brain worked like AraK's here. Read the removing `const` suggestion and pavloved to down-voting. Sorry. I'll remove my down-vote (but won't up-vote as long as you suggest removing `const`).
sbi
@sbi these are the syndromes of overtime on SO ;)
AraK
@sbi and what if I want to increment a counter in PrintLessonName() that will count how many print where done. agree not the best code in the world but possible. Also as a rule of thumb don't put const on virtual methods since you don't know how someone is going to use them.
Shay Erlichmen
@AraK: Actually not. It's more a syndrome of me stealing precious time somewhere else to be here and then not reading thoroughly because I feel like I steal to much. `:)`
sbi
@Shay: That depends. If that counter is something users of that lesson can observe, then going against expectations might be worth considering. If not, then that counter isn't part of the logical constness of the object and it should probably be `mutable`.
sbi
+10  A: 

PrintLessonName must be declared as const to be able to be called on const ILessons. Otherwise the compiler assumes it may modify the ILesson and prevents the call.

virtual void PrintLessonName() const = 0;
John Kugelman
+3  A: 

You have to make PrinLessonName const.

virtual void PrintLessonName() const = 0;

Or not use a const_iterator, of course.

yeyeyerman
+3  A: 

You want a list of pointers to ILesson's.

IMO, you'd also be considerably better off adding something like:

std::ostream &operator<<(std::ostream &os, ILesson const *il) { 
    il->PrintLessonName(os);
    return os;
}

Then, instead of the loop you've written above, you can use something like:

std::copy(lessons.begin(), lessons.end(), 
          std::ostream_iterator<ILesson *>(std::cout));

As you can see, I've added one other minor embellishment in the process -- PrintLessonName takes a stream as its argument, instead of always printing to the same place. Of course, if you're not using streams, you may not want that...

Edit: Of course the other comments that you want to make PrintLessonPlan const are also correct...

Jerry Coffin
+1 I think this how it should be done in *C++* :)
AraK
A: 

People are correct about the lack of const. I'd favour using the for_each algorithm this will prevent calling lessons.end() for every entry.

#include <algorithm> //for for_each()

Then use this:

std::for_each(  lessons.begin(), lessons.end(), std::mem_fun(&ILesson::PrintLessonName) )
Charles Beattie
+1  A: 

A version like this:

for (TLessonList::const_iterator i=lessons.begin(), m=lessons.end();  i!=m;  ++i)
    {
        i->PrintLessonName();
    }

lessons.end() gets called once, and also note ++i instead of i++, which is faster (the post-increment operator involves creation of a temporary object, while the pre-increment doesn't).

riviera