Home > Blockchain >  Knowing when pointed to object changes
Knowing when pointed to object changes

Time:10-16

In C is there a way, using raw pointers or otherwise to trigger some action when the pointed to object changes?

Scenario:

class A
{
    double var;
    B var2 {&var};
}

class B
{
   double* pVar;
   B (double* _var ) { pVar = _var};
}

I have functions inside class B that will get called whenever member variable var changes value. At the moment I would need these functions to be public so they can be called manually from class A, this could be achieved by using a setter for var. If I wanted to keep the function inside class B private (as it is called by other events internal to class B) what are my options?

CodePudding user response:

This is an example of the observer pattern. So what you need is to trigger a function call to another object when the value of your object is changed through a setter method.

#include <functional>
#include <iostream>

//-----------------------------------------------------------------------------
// the class with the member variable that can change
// and to which another class can react.
// This is a simple example where only one "callback" function
// can be registered. In the typical observer pattern
// there can be multiple callbacks registered.

class Observee
{
public:

    // set notification function to a function that does nothing
    // "null strategy pattern"
    Observee() :
        m_notify_observer_fn{ [](int) {} }
    {
    }

    // let another object pass in a function that will be called
    // when the value is changed
    void OnValueChanged(std::function<void(int)> notify_observer_fn)
    {
        m_notify_observer_fn = notify_observer_fn;
    }

    // to change the member value AND notify the other object
    // that the value has changed we need a setter function.
    void set_value(int value)
    {
        // check if the value really has changed
        if (m_value != value)
        {
            // set the member value
            m_value = value;

            // then notify the observer of the new value
            // by calling the notification function
            m_notify_observer_fn(m_value);
        }
    }

private:
    std::function<void(int)> m_notify_observer_fn;
    int m_value{};
};

//-----------------------------------------------------------------------------
// The class that wants to get a notification when the value
// of the other class changes (role is an Observer)

class Observer
{
public:
    explicit Observer(Observee& observee)
    {
        // Set the callback in the observee to the OnValueChanged
        // function of this object (the function passed is called a lambda funtion)
        observee.OnValueChanged([this](int value)
        {
            OnValueChanged(value);
        });
    }

private:
    void OnValueChanged(int value)
    {
        std::cout << "Value changed to " << value << "\n";
    }
};

//-----------------------------------------------------------------------------

int main()
{
    // make instances of both classes.
    Observee observee;
    Observer observer{ observee };

    // now set the value
    // this will change the member in observee
    // and then call the method in the observer for you
    observee.set_value(42);

    return 0;
}

CodePudding user response:

Question : If I wanted to keep the function inside class B private (as it is called by other events internal to class B) what are my options?

You can call a private function of class B while coding class A using friend attribute.

class B 
{
    friend class A;
private:
    void foo() { std::cout << "using foo." << std::endl; }
};

class A
{
private:
    B b;
public:
    void bar(){ b.foo(); }
};

int main()
{
    A a;
    a.bar();
    return 0;
}

About the callback to be call when a double variable change its value: No you can't do it with a raw pointer.

You got at least two ways of doing it. The first way is what you outlined : use a setter function. The second is to make a class that own the value and that overloading operator= is able to call the callback. I'll sketch something here to make you understand better:

template<class T>
class Owner{
    using FuncType = std::function<void(Owner<T>&)>;
    
public:
    Owner(){}
    Owner(const T& init){
        _var = init;
    }
    Owner(const Owner<T>& init){
        _var = init;
    }
    operator T(){
        return _var;
    }
    auto& operator =(const T& rvalue){
        _var = rvalue;
        _on_change();
        return *this;
    }
    auto& operator =(const Owner<T>& rvalue){
        _var = rvalue;
        _on_change();
        return *this;
    }
    const T& get() const { //don't make it non const or
                           //you will lose ownership to value of _var
        return _var;
    }
    void set(const T& val){
        _var = val;
        _on_change();
    }
    void set(const Owner<T>& val){
        _var = val;
        _on_change();
    }
    
    void set_handler(FuncType func)
    {
        _func = func;
    }
    
    
private:
    void _on_change(){
        if(_func)
            _func(*this);
    }
    
private:
    T _var{};
    FuncType _func{};
};



int main()
{
    Owner<double> var{};
    var.set_handler([](Owner<double>& ch){
        std::cout << "Value changed: " << (double) ch << std::endl;    
    });
    
    var = 1.0;
    return 0;
}
  • Related