对于重载函数,调用父子实例的专用版本

2022-01-24 00:00:00 inheritance overloading polymorphism c++

我早些时候问了一个问题,但事实证明我的问题没有通过我的示例正确建模.所以这是我的实际问题:

I asked a question earlier but it turns out my problem was not properly modeled by my example. So here is my actual problem:

  1. 我有类 A,类 B 继承自 A
  2. 我有两个函数 foo(A&)foo(B&),
  3. 我有一个 A* 指针列表,其中包含 AB 的实例.
  4. 如何为 A 的实例调用 foo(A&) 的实例调用 foo(B&)>B?约束:我可以修改AB的实现,但不能修改foo的实现.
  1. I have class A, and class B inheriting from A,
  2. I have two functions foo(A&) and foo(B&),
  3. I have a list of A* pointers, containing instances of A and B.
  4. How do I get to call foo(A&) for instances of A and foo(B&) for instances of B? Constraints: I can modify A and B implementation, but not foo's implementation.

看下面的例子:

#include <iostream>
#include <list>

class A {
public:
};

class B : public A {
public:
};

void bar(A &a) { std::cout << "This is an A" << std::endl; }
void bar(B &b) { std::cout << "This is a B" << std::endl; }

int main(int argc, char **argv) {
  std::list<A *> l;
  l.push_back(new B());
  l.push_back(new B());
  for (std::list<A *>::iterator it = l.begin(); it != l.end(); ++it)
    bar(**it);
}

虽然我使用的是带有指针的容器,但 bar 是用父类中的对象调用的,而不是子类:

Although I am using a container with pointers, bar is called with object from the parent class, not the child class:

# ./a.out
This is an A
This is an A
#

我期待

This is a B

将指针传递给 bar(通过重写其签名)没有帮助.

Passing pointers to bar (by rewriting its signature) does not help.

感谢 Antonio 帮助澄清问题.

Thx to Antonio for helping clarifying the question.

推荐答案

由于重载是在编译时解决的,你需要为编译器提供足够的信息来决定 bar 的正确重载称呼.由于您希望根据对象的运行时类型动态地做出决定,因此虚函数会很有帮助:

Since overloading is resolved at compile time, you need to supply the compiler with enough information to decide on the proper overload of bar to call. Since you wish to make that decision dynamically based on the run-time type of the object, virtual functions would be of great help:

struct A {
    virtual void bar() { bar(*this); }
};

struct B : public A {
    virtual void bar() { bar(*this); }
};

可能看起来身体是相同的,所以 B::bar 可以被消除,但事实并非如此:虽然身体看起来完全一样,但它们调用不同的 bars 由于 C++ 中重载的静态解析:

It may seem like the bodies are identical, so B::bar could be eliminated, but this is not true: although the bodies look exactly the same, they call different bars due to the static resolution of overloads in C++:

  • A::bar内部*this的类型是A&,所以调用了第一个重载.
  • B::bar内部*this的类型是B&,所以调用了第二个重载.
  • Inside A::bar the type of *this is A&, so the first overload is called.
  • Inside B::bar the type of *this is B&, so the second overload is called.

修改调用代码调用成员bar即可完成更改:

Modify the calling code to call the member bar will complete the change:

std::list<A *> l;
l.push_back(new B());
l.push_back(new B());
for (std::list<A *>::iterator it = l.begin(); it != l.end(); ++it)
    (*it)->bar();

相关文章