开发者

C++ Interfaces in stl::list

开发者 https://www.devze.com 2022-12-09 05:34 出处:网络
LessonInterface class ILesson { public: virtual void PrintLessonName() = 0; virtual ~ILesson() {} }; stl container

LessonInterface

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

stl container

typedef list<ILesson> TLessonList;
开发者_Python百科

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


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;


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.


You have to make PrinLessonName const.

virtual void PrintLessonName() const = 0;

Or not use a const_iterator, of course.


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...


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

virtual void PrintLessonName() const = 0


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.


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).


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) )
0

精彩评论

暂无评论...
验证码 换一张
取 消