是在重载解析中实际选择的纯虚函数

Is a pure virtual function actually selected in overload resolution?

本文关键字:选择 函数 重载      更新时间:2023-10-16

摘自我对上一个问题的评论:

由于不能有抽象类的实例,因此在重载解析之后永远不能选择纯虚函数

明显的反应是:

abstract_class* a = new derived_class; a->pure_virtual_function();

和最好的正确性证明:

动态分派发生在运行时,基于当时实际使用的对象。重载解析在编译时发生。


然而,令我困扰的是,当显式解析类成员的作用域时,在我们的案例编译中,失败了,所以看起来pure virtual function实际上从未通过重载解析被选中:

struct B
{
    virtual void copy(B const& rhs) = 0;
};
struct D : B
{
    void copy(B const& rhs)
    {
        D const *pd = dynamic_cast<D const*>(&rhs);
        if (pd) {
            y = pd->y;
        }
    }
    int y;
};
int main()
{
    D d1, d2; 
    d1.y = 2;
    d2.y = 5;
    B *p1(&d1), *p2(&d2); 
    ////////////////////////////////////////////
    (*p1).B::copy(*p2);
    ////////////////////////////////////////////
    return 0;
}

错误消息

对' B::copy(B const&)'的未定义引用

这里的情况是什么,如果纯虚函数实际上是在重载解析中选择的,为什么我不能"强制"编译器做同样的事情(就像解析一样)

可以通过重载解析选择纯虚函数。在大多数情况下,它不会被调用。它的最终重写将被调用,就像其他虚函数一样。

struct A
{
  virtual void foo() = 0;
  void foo(int);
};
A* getA();
int main ()
{
   A* a = getA();
   a->foo();
}
struct B : A
{
  void foo() {}
};
A* getA()
{
  return new B;
}

重载解析在编译时选择A::a() (而不是 B::a()),然后在运行时通过虚拟调度机制找到B::a()并调用。纯度在这里无关紧要

如果我没理解错的话,你其实有两个问题。这两个地址都在这里:

为什么编译失败?

失败是因为您显式地尝试调用没有实现的纯虚函数。但是,可以实现纯虚函数。下面是一个单行实现,它将使您的代码成功编译并运行:

void B::copy(B const& rhs) { std::cout << "I am pure and virtuousn"; }

是否在重载解析中实际选择了纯虚函数?

总之,不,不是在这种情况下。但是有一种情况,纯虚函数必须实现,并且将被调用(但严格地说,不是由于重载解析)。这种情况发生在基类存在纯虚析构函数的情况下。

但是,在重载解析中可以选择纯虚函数。添加到B
void B::copy(B const& rhs) const { std::cout 
         << "I am pure and virtuous and constantn"; }

D中相应的函数:

void copy(B const& rhs) const { /* do nothing */ }

你会发现重载解析只会导致"I am pure and virtuous"被打印。