[SOLVED-ISH] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
User avatar
tanderson69
Posts: 1536
Joined: Thu Feb 18, 2010 1:07 am

Re: Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby tanderson69 » Tue Nov 12, 2019 3:53 pm

DeepSOIC wrote:
Tue Nov 12, 2019 2:38 pm

Code: Select all

// Example program
#include <iostream>

class BaseClass
{
    int basemember = 0;
};

class A : public BaseClass
{
public:
    int mmA = 0;
public:
    A& operator=(A& other) {
        mmA = 0;
    }
};

class B: public A
{
public:
    int mmB = 0;
    B(int mma, int mmb){
        mmA = mma;
        mmB = mmb;
    }
};

int main()
{
    A* inst1 = new B(1,1);
    A* inst2 = new B(2,2);
    
    *static_cast<A*>(inst1) = *static_cast<A*>(inst2);
    
    std::cout << "inst1 " << inst1->mmA <<" " << static_cast<B*>(inst2)->mmB <<"\n"; 
    
    delete inst1;
    delete inst2;
    
}
result: mmA reset to zero, mmB copied. I never expected C++ to be that smart :shock: , I thought it will just call the operator= of A and be done with it, I didn't expect it to copy members of B.
:mrgreen: THANKS!!
I might be confused but, I think you should look at this again. When you cast to A and call 'operator=', you ARE using 'A::operator='. I think you used the wrong instance in your cast to std::cout and this made you believe that 'B::operator=' was being used :?:
User avatar
DeepSOIC
Posts: 7616
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: [SOLVED] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby DeepSOIC » Tue Nov 12, 2019 3:57 pm

tanderson69 wrote:
Tue Nov 12, 2019 3:53 pm
I think you used the wrong instance in your cast to std::cout and this made you believe that 'B::operator=' was being used
Good catch :| :cry:
User avatar
DeepSOIC
Posts: 7616
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: [SOLVED] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby DeepSOIC » Tue Nov 12, 2019 3:59 pm

what a bummer, not even calling BaseClass::operator= helps :cry: :cry: :cry:
User avatar
DeepSOIC
Posts: 7616
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: [REOPENED] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby DeepSOIC » Tue Nov 12, 2019 4:08 pm

The suggestion by wmayer does work. But that means I have to have my pointers pre-casted to the final type. So, overriding copy() method in every constraint is unavoidable :( . But at least I don't have to list the members, so that's better than nothing.
User avatar
tanderson69
Posts: 1536
Joined: Thu Feb 18, 2010 1:07 am

Re: [REOPENED] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby tanderson69 » Tue Nov 12, 2019 4:51 pm

DeepSOIC wrote:
Tue Nov 12, 2019 4:08 pm
But that means I have to have my pointers pre-casted to the final type.
Not necessarily. I think your first try using a virtual function was the correct way. You just can't use virtual functions with different argument types like copy constructors and assignment operators. A common solution to this is to create a separate virtual copy/assignment member functions in the base class. Then each subclass will override and call the copy constructor or assignment operator. Of course there will be some type checking but it should be hidden from the calling code.
User avatar
DeepSOIC
Posts: 7616
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: [SOLVED-ISH] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby DeepSOIC » Tue Nov 12, 2019 4:59 pm

tanderson69 wrote:
Tue Nov 12, 2019 4:51 pm
...A common solution to this is to create a separate virtual copy/assignment member functions in the base class. Then each subclass will override and call the copy constructor or assignment operator. Of course there will be some type checking but it should be hidden from the calling code.
Any specific code you can suggest?
Taking my snippets as a base, can something be done without explicitly writing "mmB = other.mmB"? There will be a LOT of variants of B, so I want to minimize red-herrings.

This is the best I've come up with so far:

Code: Select all

// Example program
#include <iostream>

class BaseClass
{
    int basemember = 0;
};

class A : public BaseClass
{
public:
    int mmA = 0;
public:
    virtual A& operator=(A& other) {
        BaseClass::operator=(other);
        mmA = 0;
    }
};

class B: public A
{
public:
    int mmB = 0;
    B(int mma, int mmb){
        mmA = mma;
        mmB = mmb;
    }
    //virtual B& operator=(A& other) override = default;
        
};

int main()
{
    A* inst1 = new B(1,1);
    A* inst2 = new B(2,2);
    
    *static_cast<B*>(inst1) = *static_cast<B*>(inst2); // same but with no static casts has to be put into an override of copy() in each version of B, then
    
    std::cout << "inst1 " << inst1->mmA <<" " << static_cast<B*>(inst1)->mmB <<"\n"; 
    
    delete inst1;
    delete inst2;
    
}
BTW, cpp.sh/ is a convenient place to try these test snippets...
User avatar
tanderson69
Posts: 1536
Joined: Thu Feb 18, 2010 1:07 am

Re: [SOLVED-ISH] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby tanderson69 » Tue Nov 12, 2019 5:57 pm

DeepSOIC wrote:
Tue Nov 12, 2019 4:59 pm
Any specific code you can suggest?
Here is an example of what I mean:

Code: Select all

// Example program
#include <iostream>
#include <cassert>
#include <memory>

class BaseClass
{
public:
    int basemember = 0;
    virtual void assign(const BaseClass *other) = 0;
};

class A : public BaseClass
{
public:
    int mmA = 0;
    void assign(const BaseClass *other) override
    {
        const A* otherPtr = dynamic_cast<const A*>(other);
        assert(otherPtr);
        *this = *otherPtr;
    }
};

class B: public A
{
public:
    int mmB = 0;
    B(int mma, int mmb){
        mmA = mma;
        mmB = mmb;
    }
    void assign(const BaseClass *other) override
    {
        const B* otherPtr = dynamic_cast<const B*>(other);
        assert(otherPtr);
        *this = *otherPtr;
    }
};

int main()
{
    std::unique_ptr<A> inst1 = std::make_unique<B>(1,1);
    std::unique_ptr<A> inst2 = std::make_unique<B>(2,2);
    
    inst1->assign(inst2.get());
    
    std::cout << "inst1 " << inst1->mmA <<" " << static_cast<B*>(inst1.get())->mmB <<"\n"; 
}


DeepSOIC wrote:
Tue Nov 12, 2019 4:59 pm
so I want to minimize red-herrings.
;) Good luck with that.
User avatar
DeepSOIC
Posts: 7616
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: [SOLVED-ISH] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby DeepSOIC » Tue Nov 12, 2019 6:08 pm

I think I am leaning towards the simplest solution there is: no copy(). Because I can't think of a reason where I actually need a shallow copy (there used to be one, I wanted to make solver and constraint to communicate via some member variables, and that required copying the constraints for each solver. But I chose a different strategy there).

The thing I may want a deep copy for is for copying the whole problem, i.e. a combo of parameters, geometries and constraints. But that requires some wonderful choreography, which I would like to avoid for now.
aapo
Posts: 114
Joined: Mon Oct 29, 2018 6:41 pm

Re: Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby aapo » Tue Nov 12, 2019 8:20 pm

wmayer wrote:
Tue Nov 12, 2019 2:41 pm
I guess it's the code analyzer of QtCreator that complains about it, right? A few months ago I tried to change a few things to make the code analyzer happy with things like the export macro and a few other issues. However, the analyzer has big problems to understand forward declarations and thus will flood you with false-positive warnings. So, I disabled it again.

Btw, here the analyzer is right and to fix this specific warning you have to add these two lines:

Code: Select all

  BaseClass(const BaseClass&) = default;
  BaseClass& operator=(const BaseClass&) = default;
I think modern compilers might give a warning, if you break the rule of three: https://en.wikipedia.org/wiki/Rule_of_t ... ogramming)
wmayer
Site Admin
Posts: 15971
Joined: Thu Feb 19, 2009 10:32 am

Re: [SOLVED-ISH] Advice wanted on designing a c++ class managed by python: Constraint (baseclass)

Postby wmayer » Tue Nov 12, 2019 10:15 pm

I think modern compilers might give a warning, if you break the rule of three: https://en.wikipedia.org/wiki/Rule_of_t ... ogramming)
It's a question of which warnings are enabled. On my Linux system when I build with clang with -Wall -Wextra -Wpedantic then these warnings are not reported.

Edit:
According to https://clang.llvm.org/docs/DiagnosticsReference.html one must use the option: -Wdeprecated