c++ 调用 base class 方法切片对象
c++ call to base class method slices object
我有这样的东西:
#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 ?
这里没有切片,因为你小心地通过引用传递对象;切片需要按值操作对象。
效果是由于过载解析,它是静态完成的(即在编译时)。 C++编译这个成员函数时
void A::bar(X &x) {
x.foo(*this);
}
它需要在编译时决定选择两个重载中的哪一个。决定很简单:编译器知道 *this
是 A
类型,所以它调用 void foo(A &a)
函数。
如果不使用模板在 B
* 中实现相同的方法,或者使用函数对象或 lambda 实现您自己的调度方案,您将无法让它工作。
* 在这种情况下,您最终会得到 Visitor Pattern, a technique of implementing Double Dispatch.
的近乎经典的 C++ 实现
我有这样的东西:
#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 ?
这里没有切片,因为你小心地通过引用传递对象;切片需要按值操作对象。
效果是由于过载解析,它是静态完成的(即在编译时)。 C++编译这个成员函数时
void A::bar(X &x) {
x.foo(*this);
}
它需要在编译时决定选择两个重载中的哪一个。决定很简单:编译器知道 *this
是 A
类型,所以它调用 void foo(A &a)
函数。
如果不使用模板在 B
* 中实现相同的方法,或者使用函数对象或 lambda 实现您自己的调度方案,您将无法让它工作。
* 在这种情况下,您最终会得到 Visitor Pattern, a technique of implementing Double Dispatch.
的近乎经典的 C++ 实现