重载 - >运算符通过代理转发成员访问
Overload -> operator to forward member-access through Proxy
我正在尝试将 Python PyObject*
包装在 Object
类中。在Python中,一切都是PyObject*
。列表是一个PyObject*
,列表中的每个项目本身就是一个PyObject*
。这甚至可能是另一个列表。等。
我正在尝试通过代理模式(此处)允许fooList[42] = barObj
样式语法。
现在我已经可以工作了,我想扩展它,以便fooList[42]
可以用作Object
。具体来说,我希望能够处理...
fooList[42].myObjMethod()
fooList[42].myObjMember = ...
Object
有很多方法,目前fooList[42].myObjMethod()
将首先将fooList[42]
解析为Proxy
实例,例如tmpProxy
,然后尝试tmpProxy.myObjMethod()
。
这意味着我必须这样做
void Proxy::myObjMethod(){ return wrapped_ob.myObjMethod(); }
即手动通过Proxy
传递Object
的方法,这是丑陋的。
我看不到任何完美的解决方案(请参阅上面的链接答案),但我很乐意使用:
fooList[42]->myObjMethod()
。作为折衷方案,视为 -> 可以重载(而不是不能重载.
)。
但是,我找不到任何有关重载operator->
的文档。
我最好的猜测是它必须返回指向某个对象的指针(比如pObj
),C++会调用pObj->whatever
。
下面是我尝试的实现。但是,我遇到了"获取对象类型的临时对象的地址"警告。
在我的Object
班中,我有:
const Object operator[] (const Object& key) const {
return Object{ PyObject_GetItem( p, key.p ) };
}
请注意,"const Object&"遇到"获取对象类型的临时对象的地址"警告。
class Proxy {
private:
const Object& container;
const Object& key;
public:
// at this moment we don't know whether it is 'c[k] = x' or 'x = c[k]'
Proxy( const Object& c, const Object& k ) : container{c}, key{k}
{ }
// Rvalue
// e.g. cout << myList[5] hits 'const Object operator[]'
operator Object() const {
return container[key];
}
// Lvalue
// e.g. (something = ) myList[5] = foo
const Proxy& operator= (const Object& rhs_ob) {
PyObject_SetItem( container.p, key.p, rhs_ob.p );
return *this; // allow daisy-chaining a = b = c etc, that's why we return const Object&
}
const Object* operator->() const { return &container[key]; }
// ^ ERROR: taking the address of a temporary object of type Object
};
这个想法是允许myList[5]->someMemberObj = ...
样式语法。
myList[5]
解析为Proxy
实例,它包装Object
(myList
的第六个元素)。我们称之为myItem
.
现在我希望someProxy->fooFunc()
或someProxy->fooProperty
分别调用myItem.fooFunc()
或myItem.fooProperty
。
我遇到了"获取对象类型的临时对象的地址"警告。
如果可以更改Object
,则可以添加
class Object {
public:
// other code
const Object* operator -> () const { return this; }
Object* operator -> () { return this; }
};
为了您的Proxy
Object operator->() { return container[key]; }
所以,例如
myObj[42]->myFoo = ...
大多等同于
Proxy proxy = myObj[42];
Object obj = proxy.operator ->();
Object* pobj = obj.operator ->(); // so pobj = &obj;
pobj->myFoo = ...
我发现您作为示例编写的Proxy
类有点令人困惑,所以我冒昧地对其进行了一点更改:下面是一个简单的示例:
//object with lots of members:
class my_obj
{
public:
std::string m_text;
void foo()
{
std::cout << m_text << std::endl;
}
void bar(std::string t)
{
m_text = t;
}
};
//proxy object
class proxy_class
{
private:
friend class CustomContainer;
my_obj* px;
proxy_class(my_obj * obj_px)
:px(obj_px)
{
}
proxy_class() = delete;
proxy_class(const proxy_class &) = delete;
proxy_class& operator =(const proxy_class &) = delete;
public:
my_obj* operator ->()
{
return px;
}
};
//custom container that is the only one that can return proxy objects
class CustomContainer
{
public:
std::map<std::size_t, my_obj> stuff;
proxy_class operator [](const std::size_t index)
{
return proxy_class(&stuff[index]);
}
};
用法示例:
CustomContainer cc;
cc[0]->foo();
cc[0]->bar("hello world");
cc[0]->foo();
作为设计考虑因素,应在受控环境中创建代理类,以便删除构造函数以防止误用。
CustomContainer
只需要返回带有对my_obj
引用的proxy_class
,这样它就可以使用任何东西,std::map
,std::vector
等
经过几个小时的哄骗大肠杆菌,我有一个工作测试用例。
请参考: https://codereview.stackexchange.com/questions/75237/c11-proxy-pattern-for-supporting-obidx-someobjmember-type-acc
非常感谢 Jarod,为 -> 重载提供了正确的语法和理解。
- 代理对象的常量正确性
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 正在折叠转发引用
- 具有所表示类的相同构造函数签名的代理类模板
- 将函数参数完美转发到函数指针:按值传递呢?
- 转发变量参数列表以模拟 std::thread
- 在按值调用 (c++) 中转发构造函数参数
- 存储稍后要转发的变量参数
- 如何在 C++ 中转发声明 std::set?
- C++使用默认模板参数键入别名和转发声明
- CNTK:->转发或 ->评估某些电脑上的崩溃,而不是其他电脑上的崩溃
- C++20理念:要求表达和完美转发
- 如何在模板中转发右值和左值引用
- 如何转发声明枚举?
- 使用函数指针转发声明作为 lamba 声明
- CAFFE转发网络在for循环中不起作用
- C++封装成员的完美转发/代理
- 重载 - >运算符通过代理转发成员访问
- 将所有流量转发到http代理(隧道)
- 代理dll:方法覆盖/方法转发(COM实现继承)