问题
I have something like this:
#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;
}
Compile it and execute it, you'll have:
# ./a.out
foo A
#
I believe this is because object is sliced when cast to A. How can I avoid this so I get
foo B
without implementing the method in B or using some weirdness like the Curiously recurring template pattern ?
回答1:
No slicing is going on here, because you carefully pass objects by reference; slicing requires manipulating the object by value.
The effect is due to overload resolution, which is done statically (i.e. at compile time). When C++ compiles this member function
void A::bar(X &x) {
x.foo(*this);
}
it needs to decide, at compile time, which of the two overloads to pick. The decision is simple: the compiler knows that *this
is of type A
, so it calls void foo(A &a)
function.
You cannot get it to work without implementing the same method in B
*, using templates, or implementing your own dispatch scheme with function objects or lambdas.
* in which case you would end up with a nearly classic C++ implementation of the Visitor Pattern, a technique of implementing Double Dispatch.
来源:https://stackoverflow.com/questions/29488392/c-call-to-base-class-method-slices-object