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;
}