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

C++ 在重载解析中是否实际选择了纯虚拟函数?,c++,C++,根据我在上一个问题中的评论: 因为抽象类的实例不可能存在,所以在重载解析之后,绝对不能选择纯虚函数 明显的反应是: abstract_class* a = new derived_class; a->pure_virtual_function(); 最好的正确证明是: 动态调度发生在运行时,基于当时实际使用的对象。重载解析发生在编译时 然而,让我烦恼的是,当在我们的例子中显式解析类成员的作用域时,编译失败了,因此它看起来像是一个纯虚拟函数,实际上从未通过重载解析被选中: struct

根据我在上一个问题中的评论:

因为抽象类的实例不可能存在,所以在重载解析之后,绝对不能选择纯虚函数

明显的反应是:

abstract_class* a = new derived_class; a->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 { 虚拟无效副本(B常量和rhs)=0; }; 结构D:B { 无效副本(B const和rhs) { D const*pd=动态施法(&rhs); 如果(pd){ y=pd->y; } } int-y; }; int main() { D d1、d2; d1.y=2; d2.y=5; B*p1和d1、*p2和d2; //////////////////////////////////////////// (*p1.B::复制(*p2); //////////////////////////////////////////// 返回0; } 错误消息 对“B::copy(B const&)”的未定义引用


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

如果我理解,你真的有两个问题。这两个问题都在这里解决:

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

void B::copy(B const& rhs) { std::cout << "I am pure and virtuous\n"; }
以及
D
中的相应函数:

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

您会发现重载解析只会导致打印“我是纯洁的和有道德的”。

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

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()
)。纯度与此无关。

可以在过载分辨率中选择纯虚拟函数。你能澄清问题的最后一部分吗(粗体)?用类名显式限定禁用动态分派。但是这与重载解析无关。它失败是因为选择了纯虚拟,并且没有定义它。注意在这个例子中,没有重载解析,因为没有重载。如果您添加了一个带有另一个签名的
copy
方法,则会有重载解析,但在这种情况下,如果匹配得更好,则仍会选择纯虚拟,并且仍然会出现链接故障。你的“上一个问题的评论”是错误的。你把重载和覆盖混淆了吗?@NikosAthanasiou:答案是正确的,评论是完全错误的,也是不正确的。正如Oktalist评论的那样,您似乎混淆了重载解析和动态调度,它们是完全独立的事情,尽管两者都可以在一个函数调用中发生。您可能的意思是“纯虚拟函数永远不能通过动态分派来选择”,这是真的(在CTOR/DTOR中使用虚拟调用的模未定义行为)
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;
}