【问题标题】:Knowing when pointed to object changes知道何时指向对象更改
【发布时间】:2021-12-02 21:53:36
【问题描述】:

在 C++ 中有没有一种方法,使用原始指针或其他方式在指向对象发生变化时触发某些操作?

场景:

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

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

我在 B 类中有函数,只要成员变量 var 更改值,就会调用这些函数。目前我需要将这些函数公开,以便可以从 A 类手动调用它们,这可以通过使用 var 的 setter 来实现。如果我想让 B 类中的函数保持私有(因为它被 B 类内部的其他事件调用),我有什么选择?

【问题讨论】:

  • 简而言之:不,没有。
  • 你不能用原始指针做到这一点。你应该阅读观察者设计模式。
  • 这个问题的标题和第一句话是关于一件事,但问题的其余部分是关于从另一个类调用私有成员函数。无论如何,当变量发生变化时,没有办法神奇地调用函数。如果你想使用 setter 函数做类似的事情,可能让 A 接受从 var 的 setter 调用的回调。通过friend 处理私人/公共问题。
  • 您的问题本质上与要求“在int 更改时触发操作”相同。指针是与大多数其他值一样的值。
  • 核心 C++ 语言中没有内置这样的工具。 Boost Signals2 提供了这种功能,我认为它是在 Qt 的信号和插槽之后设计的。

标签: c++ c++11 c++17


【解决方案1】:

这是观察者模式的一个例子。 所以你需要的是触发对另一个对象的函数调用 当您的对象的值通过 setter 方法更改时。

#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;
}

【讨论】:

  • 我也喜欢你的方法
【解决方案2】:

问题:如果我想让 B 类中的函数保持私有(因为它被 B 类内部的其他事件调用),我有什么选择?

您可以在使用朋友属性对A类进行编码时调用B类的私有函数。

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;
}

关于双变量更改其值时要调用的回调: 不,你不能用原始指针来做。

您至少有两种方法。 第一种方法是您概述的:使用 setter 函数。 第二个是创建一个拥有该值并且重载 operator= 能够调用回调的类。 我会在这里画一些草图让你更好地理解:

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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-18
    • 2012-03-27
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多