C ++调用基类方法slices对象 [英] c++ call to base class method slices object

查看:115
本文介绍了C ++调用基类方法slices对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的东西:

#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中实现该方法,也没有使用诸如好奇地重复的模板模式之类的怪异?

解决方案

这里没有切片,因为您仔细地按引用传递了对象;切片需要按值操作对象.

效果是由于重载解析导致的,该解析是静态完成的(即在编译时).当C ++编译此成员函数时

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

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

如果不使用B * 中的相同方法,使用模板或使用函数对象或lambda来实现自己的调度方案,您将无法使其正常工作.

* ,在这种情况下,您最终会使用 Visitor的几乎经典的C ++实现模式 ,一种实现 Double Dispatch 的技术.. >

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 ?

解决方案

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.

这篇关于C ++调用基类方法slices对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆