通过a";指向虚拟函数的指针;Python中的as参数
比较C++中的以下代码:通过a";指向虚拟函数的指针;Python中的as参数,python,c++,reference,virtual-functions,dispatch,Python,C++,Reference,Virtual Functions,Dispatch,比较C++中的以下代码: #include <iostream> #include <vector> struct A { virtual void bar(void) { std::cout << "one" << std::endl; } }; struct B : public A { virtual void bar(void) { std::cout << "two" << std::endl; } }
#include <iostream>
#include <vector>
struct A
{
virtual void bar(void) { std::cout << "one" << std::endl; }
};
struct B : public A
{
virtual void bar(void) { std::cout << "two" << std::endl; }
};
void test(std::vector<A*> objs, void (A::*fun)())
{
for (auto o = objs.begin(); o != objs.end(); ++o)
{
A* obj = (*o);
(obj->*fun)();
}
}
int main()
{
std::vector<A*> objs = {new A(), new B()};
test(objs, &A::bar);
}
class A:
def bar(self):
print("one")
class B(A):
def bar(self):
print("two")
def test(objs, fun):
for o in objs:
fun(o)
objs = [A(), B()]
test(objs, A.bar)
C++代码将打印:
one
two
而Python代码将被打印出来
one
one
我如何传递“一个方法指针”并将其解析为重写的方法,在Python中实现与C++(
)相同的行为?添加一些上下文并解释我最初为什么想到这个模式。我有一棵树,由可以子类化的节点组成。我想创建一个通用的图遍历函数,它接受图的一个节点以及一个可能在图节点的子类中被重写的函数。该函数根据为相邻节点计算的给定值,计算节点的某些值。目标是返回为给定节点计算的值(需要遍历整个图) 以下操作将生成所需的输出:
class A:
def bar(self):
print("one")
class B(A):
def bar(self):
print("two")
def test(objs, funcname):
noop = lambda: None
for o in objs:
getattr(o, funcname, noop)()
objs = [A(), B()]
test(objs, "bar")
关于编辑,您可以做的一件事是使用一个小包装器lambda来调用您想要引用的方法。这样,方法调用看起来像“常规python代码”,而不是基于字符串访问的复杂内容 在您的示例中,唯一需要更改的部分是调用
test
函数:
test(objs, (lambda x: x.bar()))
您是否考虑过对Python代码进行结构化,以避免尝试用不同的语言复制语义?我觉得更具python风格的方法与继承或动态调度无关。我同意,问题是我没有更好的模式来解决我的问题。有关问题描述,请参见编辑。我更喜欢Pythonic解决方案。听起来你想要访问者模式。你能发布一个(简化的)示例,说明如何用Python实现它吗?这从字面上回答了这个问题,但我认为它根本不代表OP试图实现的目标。当然这个程序不会在更复杂的例子中扩展。@uh-oh:IMO它回答了这个问题,并且代表了在Python没有指针的情况下OP试图完成的任务。此外,它应该“缩放”以及C++版本。这就是我的观点。Python没有指针或多重分派,因此我希望有一种更惯用的方法来实现相同的目标。所有这些都强化了错误的做事方式。@uh-oh:除了你,谁说了关于多重调度的事?我的答案中的代码使用继承,并展示了引用实例的变量属性的惯用方法。请随意发布您自己的答案,即使是“您不能在Python中这样做”。谢谢您的回答。我认为它确实回答了我最初提出的问题。我想到了一个类似的解决方案,但我希望有一个更干净/更好的解决方案。如果没有,我建议用“这不能在Python中以任何其他方式完成”来扩展这个答案,除了:,我也很高兴听到关于解决我的问题的最佳模式的意见(参见编辑)。这似乎是一种更干净、更具Python风格的解决问题的方法。然而,它不允许动态调度,这是可以用另一个答案(如果需要的话)来模拟的。
bar
方法调用将被动态调度。我的术语可能已关闭。我的意思是,使用这种方法,不可能处理bar
在A
和B
中采用不同参数的情况,例如,在B
中,它采用附加参数。在字符串方法中,test
可以根据obj
的类型选择对bar
应用不同的参数。让A和B采用不同的参数会很奇怪(使用通用方法的目的是共享一个接口…)但并没有什么可以阻止测试检查objs列表中对象的类型。唯一的问题是如果A和B采用不同数量的参数,但您可以通过将lambda转换为vararg函数来解决:lambda x,*args:x.bar(*args)
同意这是一种比我自己的答案更好的方法。向上投票。。。