[C++-sig] boost::python - how to pass by reference/pointer to python overriden class functions

Jay Riley super24bitsound at hotmail.com
Wed May 25 23:26:42 CEST 2011


Hi all,

Hopefully this is the correct way to post a question, If not I apologize as I haven't used mailing lists before.

Anyways, here is my problem:

I have some class functions that takes in parameters by pointer. However, when I expose and override this class/these functions in boost::python, any changes I make to the parameters are not reflected back to the original, meaning it isn't being passed by pointer as I expect. I previously had them as pass-by-reference, but the same problem still occurred. For an example of what I mean, here's some of my code with unimportant functions and details omitted. 

    class StatusEffect
    {
    public:
          virtual void TickCharacter(Character::BaseCharacter* character, Battles::BattleField *field, int ticks = 1);
    }

    //In my Scripting Code header file
            
    struct StatusEffectWrapper : Game::StatusEffects::StatusEffect
    {
        virtual void TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks = 1);
        virtual void TickCharacterDefault(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks = 1);
    }

    //In the actual scripting code
        void StatusEffectWrapper::TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
        {
             call_method<void>(self, "TickCharacter", character, field, ticks);
        }
        void StatusEffectWrapper::TickCharacterDefault(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
        {
            this->StatusEffect::TickCharacter(character, field, ticks);
        }
        
        class_<StatusEffects::StatusEffect, boost::shared_ptr<StatusEffectWrapper> >("StatusEffect")
        .def("TickCharacter", &StatusEffect::TickCharacter, &StatusEffectWrapper::TickCharacterDefault)

and finally in my Python file, I try and do something like this


    class StatCreepEffect(StatusEffect):
        def __init__(self, name, stat_, rate_, descript, uid, turns, prior, canrefresh, poseffect, cats, conds, flgs, sep, pers):
            StatusEffect.__init__(self, name, descript, uid, turns, prior, canrefresh, poseffect, cats, conds, flgs, sep, pers)
            self.rate = rate_
            self.stat = stat_
        def TickCharacter(self, Character, Field, Ticks):
            if (self.stat == Stat.HP):
                Character.SetHP(int(round(Character.GetHP() + Character.GetInBattleStat(self.stat) * self.rate)))
                print("HP Regenerated on character " + Character.GetName() + " New HP: " + str(Character.GetHP()))
            elif (self.stat == Stat.MP):
                Character.SetMP(int(round(Character.GetMP() + Character.GetInBattleStat(self.stat) * self.rate)))
            elif (self.stat == Stat.SP):
                Character.SetSP(int(round(Character.SetSP() + Character.GetInBattleStat(self.stat) * self.rate)))
    
    Regen = StatCreepEffect("Regen", Stat.HP, 0.05, "Regenerates a small amount of HP every turn", PrimaryEngine.GetUID(), 14, 0, True, True, StatusCategories.SC_Regen, 0, StatusFlags.TickEffect, True, StatusPersistence.SP_Timer_Cure)
    
    SELibrary.AddPythonEffect(Regen);

If it matters, the AddPythonEffect is defined as follows:



    void StatusEffectsLibrary::AddPythonEffect(boost::shared_ptr<StatusEffect> effect)

    {

        if (effect.get() != nullptr)

        {

            NameToSEMap[effect->GetName()] = effect;

            IDToSEMap[effect->GetUID()] = effect;

        }

    }

I call the effect like so in my C++ code

    StatusEffect* regen = game.GetSELibrary().GetStatusEffect(std::string("Regen")); //This simply does a lookup to the NameToSEMap inside the StatusEffectLibrary and does a .get() on the shared_ptr

    while(character->GetHP() < 600)
        {
            regen->TickCharacter(character, field, 1);
            std::cout << "Character HP: " << character->GetHP() << std::endl;
        }


The script compiles and the effect is added correctly. The print line in the python script prints the correct value. The character object starts with 400 HP and the print line outputs 430. However, the std::cout line in my C++ code always outputs 400, meaning the extra 30 HP added by the script is not reflected back in the original object. For clarity, here's the console output from the above C++ code fragment:

    HP Regenerated on character Arian New HP: 430
    Character HP: 400

I've tried adding boost::non_copyable to the class wrapper but to no effect. I've replaced my pointers with pass by reference to no effect. I've switched between shared_ptr, auto_ptr, and a straight reference for the HeldType to no effect. I can confirm using shared_ptrs over regular pointers in the function does work, but I'd prefer to avoid using them unless there really isn't another way as it would be tedious and time consuming to do so. 

Can someone tell me how to get the behaviour I expect? 

To be clear, I'm not looking for the python script to take ownership of any of the parameters, nor will I be returning anything. I just want the changes made in the function to be reflected back to the passed in object.

Thanks




 		 	   		  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20110525/9140619d/attachment-0001.html>


More information about the Cplusplus-sig mailing list