C++ c++;重载和重写解析时间
为什么在运行时解决重写问题,而在编译时解决重载问题?C++ c++;重载和重写解析时间,c++,overriding,C++,Overriding,为什么在运行时解决重写问题,而在编译时解决重载问题? 是否有任何原因导致无法在编译时解析重写 是否有任何原因导致无法在编译时解析重写 假设你说的是多态性,即 #include <iostream> class Base { public: virtual void Foo() { std::cout << "Base::Foo()" << std::endl; } }; class Derived : public
是否有任何原因导致无法在编译时解析重写 是否有任何原因导致无法在编译时解析重写 假设你说的是多态性,即
#include <iostream>
class Base
{
public:
virtual void Foo()
{
std::cout << "Base::Foo()" << std::endl;
}
};
class Derived : public Base
{
public:
virtual void Foo()
{
std::cout << "Derived::Foo()" << std::endl;
}
};
重要的是要认识到,CallFoo()
对b
实际上是什么一无所知(它可能指的是Base
实例或派生的实例)。所有CallFoo()
获取的都是对Base
的引用,它不告诉任何它实际引用的内容,因此编译器在编译CallFoo()
时无法分辨它是什么。因此,确定是调用Base::Foo()
还是调用Derived::Foo()
,必然是一个运行时决策
删除virtual
关键字(禁用覆盖)将导致上述代码打印两次Base::Foo()
,而不是Base::Foo()
然后Derived::Foo()
。这是因为没有virtual
关键字,编译器只需在编译时解析对Base::Foo()
的调用
也就是说,由于虚拟函数会产生一些开销(毕竟,需要调用的正确函数是运行时决定),编译器将尽最大努力找出CallFoo()中b
的实际类型(如果可以)。在这种情况下,它将成为编译时决策。但是,这是一个实现细节。重写只在虚拟函数运行时解决,因为这就是实现的方式。非虚拟函数调用在编译时解析。为什么在运行时解析重写,而在编译时解析重载?
这实际上要视情况而定。
通常,编译器无法确定要调用的实际函数,直到运行时发生溢出时。这是因为基类指针指向的实际对象在运行时之前可能是未知的。在这种情况下,编译器别无选择,只能在运行时解析实际的函数调用。
然而,有时编译器可以智能地、决定性地检测需要调用的函数,即使是在溢出的情况下,在这种情况下,编译器也可以在编译时解析要调用的函数
在重载的情况下,编译器可以根据传递给函数的参数确定要调用的实际函数,因此编译器无需等到运行时才能解析此类调用,因为所有参数类型在编译时都是已知的,由于C++是静态类型的语言,所有类型都必须在编译时知道。C++中的函数重载可以由编译器自己来处理。在函数重载期间,编译器“修饰”函数名,技术上称为name mangling
。因此,在生成的代码中,每个重载方法都有一个单独的名称。这样,编译器知道在编译时自己调用哪个方法
在函数重写(派生类在其基类中重新定义方法)的情况下,如果基类方法是非虚拟的,那么调用哪个函数将在编译时确定。但若它是一个虚拟函数,那个么编译器就不能在编译时解析调用。必须通过对象中的虚拟指针进行虚拟表查找。这只能发生在运行时,因为只有在运行时,您才能知道您正在处理的对象。有时编译器可以智能地、最终地检测到需要调用的函数,即使是在溢出的情况下。
您有这样的例子吗?@Jesse:Check out:,是的,我引用的是一个已经证实的事实。这里没有猜测。你告诉我们——如何在编译时解决重写问题?@ildjarn:你可能想检查我答案下注释中的链接。@Als:动态多态性被完全禁用的上下文(因此与问题/对话无关)这不是我想问的。显然,要使用多态性,必须在多态上下文中。
void CallFoo(Base& b)
{
b.Foo();
}
int main()
{
Base b;
Derived d;
CallFoo(b); // calls Base::Foo()
CallFoo(d); // Calls Derived::Foo();
}