【问题标题】:boost python wrap c++ class private memberboost python wrap c++​​类私有成员
【发布时间】:2013-08-22 21:30:52
【问题描述】:

我们可以用 boost python 包装 c++ 私有构造函数吗? 我有一个单例 c++ 类,想将它包装到 python。

我们可以用 boost python 包装 c++ 私有成员函数吗?

非常感谢

【问题讨论】:

  • 这样做有什么意义?您不能将 Python 代码插入到 C++ 类中,这意味着私有成员的任何 有用 包装都将无法编译。 (是否有任何方法可以创建无用的包装器,我不能说……但谁在乎呢?)
  • @abarmert。我更新了我的问题。希望你明白我的意思
  • 如果您可以从任何地方(C++ 或 Python)调用私有构造函数或私有工厂函数,它就不再是单例了。只需包装 getInstance() 方法、getFoo() 函数、g_foo 全局,或任何你用来在 C++ 中访问单例的东西。
  • 是的,但是如果我不对构造函数做任何事情,c++ 编译就会出错。例如,如果我不包装私有构造函数,它会说 errr : xxx is private.
  • 很难想象你可能写了什么代码,你可能如何包装它,你可能做错了什么。请创建一个 SSCCE 来演示问题,以便我们为您提供帮助。

标签: c++ python boost boost-python


【解决方案1】:

使用这样的东西:

#include <boost/python.hpp>
#include <iostream>

using namespace boost::python;
using std::cout;

class Singleton
{
    private:
        Singleton()
        {
            cout << "Creating instance\n";
        }
    friend Singleton* create(); 
};

Singleton* pInstance_;
Singleton* create()
{       
    if(!pInstance_)
    {
        pInstance_ = new Singleton();
    }
    else
    {
        cout << "Using old instance\n";         
    }       
    return pInstance_;
}

BOOST_PYTHON_MODULE(cppmodule)
{
    def("create", create, return_value_policy<reference_existing_object>());
    class_<Singleton>("Singleton", no_init);
}

/* using singleton later in code */

Singleton* otherInstance_ = create();

会话:

>>> import cppmodule
Creating instance
>>> s = cppmodule.Singleton()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: This class cannot be instantiated from Python
>>> s = cppmodule.create()
Using old instance

【讨论】:

  • 谢谢尼卡金。这是对 python 用户有益的示例。但 c++ 用户将直接使用 Singleton()。它是一种防止python用户和c++用户创建新实例的方法吗?
  • @cppython,您必须将 Singleton 构造函数设为私有,并使 create() 函数成为此类的朋友。在 Python 和 C++ 中,您只能通过此函数创建实例。我更新了代码。
【解决方案2】:

单例通常会以私有可见性声明其构造函数,并提供可以访问私有构造函数的工厂函数。

class singleton
{
public:

  /// @brief Public factory function.
  static singleton& instance()
  {
    static singleton instance_;
    return instance_;
  }

private:

  // Private constructors and destructor.
  singleton()  {}
  ~singleton() {};

  singleton(const singleton&);
  singleton& operator=(const singleton&);
};

默认情况下,Boost.Python 假定公开可用的构造函数与提供给boost::python::class_ 构造函数的init-expression 匹配。为了抑制这种行为,可以将特殊的 boost::python::no_init 对象提供给 class_ 构造函数。此外,由于私有析构函数,class_ 需要通过提供 boost::noncopyable 作为模板参数来公开为不可复制。

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<singleton, boost::noncopyable>("Singleton", python::no_init);
}

在 Python 中,单例很少通过其 API 将自己呈现为单例。因此,许多 Python 开发人员可能自然希望能够通过 example.Singleton() 实例化 Python 类,而不是使用因子方法。虽然默认构造函数已通过python::no_init 公开,但可以为__init__ 定义自定义构造函数。为了正确解释 C++ 单例,通过 Boost.Python 公开的单例将使用 boost::shared_ptr 和一个无操作删除器来保存单例的句柄。这是一个完整的例子:

#include <boost/python.hpp>

/// @brief Mock up singleton class.
class singleton
{
public:
  /// @brief Public factory function.
  static singleton& instance()
  {
    static singleton instance_;
    return instance_;
  }

  void set_x(unsigned int x) { x_ = x;    }
  unsigned int get_x()       { return x_; }

private:

  // Private constructors and destructor.
  singleton() : x_(0) {}
  ~singleton() {};

  singleton(const singleton&);
  singleton& operator=(const singleton&);

private:
  unsigned int x_;
};

/// @brief No operation deleter.
void noop_deleter(void*) {};

/// @brief Helper function used to get a shared_ptr that holds
///        a singleton.
boost::shared_ptr<singleton> py_get_singleton()
{
  return boost::shared_ptr<singleton>(
    &singleton::instance(), // the instance
    &noop_deleter);         // no-op deleter
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  // Expose the singleton class, supressing the default constructor
  // via python::no_init, and providing a constructor that will return
  // a handle to the singleton.
  python::class_<singleton, boost::shared_ptr<singleton>,
                 boost::noncopyable>("Singleton", python::no_init)
    .def("__init__", python::make_constructor(&py_get_singleton))
    .add_property("x", &singleton::get_x, &singleton::set_x)
    ;
}

及其用法:

>>> import example
>>> s1 = example.Singleton()
>>> s2 = example.Singleton()
>>> s1.x
0
>>> s2.x
0
>>> s1.x = 5
>>> s2.x
5

请注意,从 Python 的角度来看,这更类似于 borg 或单态模式,因为它们共享状态,而不是身份。 (即s1.x == s2.x,但id(s1) != id(s2)。)如果Python 类也需要是单例,而不仅仅是它的状态,那么可能需要使用Python 代码而不是C++ 来实现此行为。

【讨论】:

    猜你喜欢
    • 2017-03-21
    • 2019-12-29
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多