[C++-sig] Wrapping virtual method returning void

Botos, Christopher CBotos at aer.com
Fri Feb 20 16:29:24 CET 2015


I have an example C++ base class (Song) with a virtual method (chorus) returning void that is called by another method (play) of the same class.  I want to be able to derive a python class from this and override the virtual method.  I experience the following behavior:

1. If I simply instantiate the wrapped base class in python and call play, **the virtual chorus is never entered/executed**.
2. If I create a derived class and override the virtual chorus, the derived chorus is executed correctly.
3. If I change the base class chorus to return int (or anything) instead of void, the base class chorus is executed correctly.

I have wrapped my class as described here: http://www.boost.org/doc/libs/1_43_0/libs/python/doc/v2/wrapper.html

My example C++,  python code, and output python output is below (I've tried to make it as concise as possible).  I can work around this issue in my application by having my virtual method return an unused object, although this is not ideal.  I would appreciate any other suggestions, whether I'm doing something incorrectly, or is this possibly a boost python bug?

//------------------------------------------------
//  Has virtual method returning void
//  Numbers indicate order in which the print statements should appear.
//------------------------------------------------
class Song
{
public:
    virtual ~Song(){}
    void play()
    {
        std::cout << "\n1) Base class --> Song.play" << std::endl;
        chorus();
        std::cout << "3) Base class <-- Song.play" << std::endl;
    }

    // THIS METHOD IS NEVER EXECUTED
    virtual void chorus()
    {
        std::cout << "2) Base class Song.chorus returning void" << std::endl;
    }
};

struct SongWrapper :  Song, bp::wrapper<Song>
{
    void chorus()
    {
        if (bp::override chorus = this->get_override("chorus"))
                chorus();
                return;
        Song::chorus();
        return;
    }

    void default_chorus()    {  this->Song::chorus(); }
};

//------------------------------------------------
//  Has virtual method returning int
//  Numbers indicate order in which the print statements should appear.
//------------------------------------------------
class AnotherSong
{
public:
    virtual ~AnotherSong(){}
    void play()
    {
        std::cout << "\n1) Base class --> AnotherSong.play" << std::endl;
        chorus();
        std::cout << "3) Base class <--AnotherSong.play" << std::endl;
    }

   // THIS METHOD (returning int) IS EXECUTED
    virtual int chorus()
    {
        std::cout << "2) Base class AnotherSong.chorus returning int" << std::endl;
        return 0;
    }
};

struct AnotherSongWrapper :  AnotherSong, bp::wrapper<AnotherSong>
{
    int chorus()
    {
        if (bp::override chorus = this->get_override("chorus"))
                return chorus();
        return AnotherSong::chorus();
    }

    int default_chorus()   {  return this->AnotherSong::chorus(); }
};

BOOST_PYTHON_MODULE(Songs)
{
    bp::class_<SongWrapper,boost::noncopyable>("Song")
       .def("play", &Song::play)
       .def("chorus", &Song::chorus, &SongWrapper::default_chorus)
       ;

    bp::class_<AnotherSongWrapper,boost::noncopyable>("AnotherSong")
       .def("play", &AnotherSong::play)
       .def("chorus", &AnotherSong::chorus, &AnotherSongWrapper::default_chorus)
       ;
}
#------------------------------------------------
# Python file ...
#------------------------------------------------
from Songs import Song, AnotherSong

# Base class chorus returning void is not executed: step 2 is missing in the output
s1 = Song()
s1.play()

# Derived class chorus is executed: step 2 in the output
class Chart(Song):
    def chorus(self):
        print "** 2) Derived class Chart.chorus"
c1 = Chart()
c1.play()

# Base class chorus returning int is executed: step 2 in output
s2 = AnotherSong()
s2.play()

#------------------------------------------------
# Python output ...
# In first case, step 2 is missing ... chorus was not executed
#------------------------------------------------
1) Base class --> Song.play
3) Base class <-- Song.play

1) Base class --> Song.play
** 2) Derived class Chart.chorus
3) Base class <-- Song.play

1) Base class --> AnotherSong.play
2) Base class AnotherSong.chorus returning int
3) Base class <--AnotherSong.play


________________________________

This email is intended solely for the recipient. It may contain privileged, proprietary or confidential information or material. If you are not the intended recipient, please delete this email and any attachments and notify the sender of the error.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20150220/b28a7a1b/attachment.html>


More information about the Cplusplus-sig mailing list