c ++调用基类方法切片对象

时间:2015-04-07 09:36:00

标签: c++ polymorphism overloading object-slicing

我有这样的事情:

#include <iostream>

class X;

class A {
public:
  virtual void bar(X &x);
};

class B : public A {
public:
};

class X {
public:
  void foo(A &a) { std::cout << "foo A" << std::endl; }
  void foo(B &b) { std::cout << "foo B" << std::endl; }
};

void A::bar(X &x) { x.foo(*this); }

int main(int argc, char **argv) {
  X x;
  B b;
  b.bar(x);
  return 0;
}

编译并执行它,你将拥有:

# ./a.out
foo A
#

我相信这是因为对象在被投射到A时会被切片。我怎么能避免这种情况,所以我得到了

foo B

没有在B中实现方法或使用像Curiously recurring template pattern这样的奇怪的东西?

1 个答案:

答案 0 :(得分:5)

这里没有切片,因为你通过引用小心地传递对象;切片需要按值操作对象。

效果是由重载决策引起的,这是静态完成的(即在编译时)。当C ++编译这个成员函数时

void A::bar(X &x) {
    x.foo(*this);
}

它需要在编译时决定选择哪两个重载。决定很简单:编译器知道*this属于A类型,因此它调用void foo(A &a)函数。

如果没有在B * 中实现相同的方法,使用模板或使用函数对象或lambdas实现自己的调度方案,就无法使其工作。

* 在这种情况下,您最终会得到Visitor Pattern的近乎经典的C ++实现,这是一种实现Double Dispatch的技术。