首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在c++中重写的方法:是编译时还是运行时多态性?

在c++中重写的方法:是编译时还是运行时多态性?
EN

Stack Overflow用户
提问于 2019-10-17 13:40:59
回答 2查看 1.3K关注 0票数 1

在C++中,是函数重写运行时多态还是编译时多态?我认为这是编译时多态,因为编译器很早就知道了调用适当函数所需的所有信息。正如下面的代码所示,这里的obj.disp();编译器知道obj是基类的对象,因此它将立即解析对基类的disp()函数的调用。对于obj2.disp();,编译器知道obj2是派生类的对象,因此它将调用派生类的disp()函数。我不明白为什么它被称为运行时多态。

仍然在JAVA中,人们称函数覆盖为运行时多态性。请解释一下..。

代码语言:javascript
复制
#include <iostream>
using namespace std;

class A {
public:
  void disp(){
     cout<<"Super Class Function"<<endl;
  }
};

class B: public A{
public:
  void disp(){
     cout<<"Sub Class Function";
  }
};

int main() {
  //Parent class object
  A obj;
  obj.disp();
  //Child class object
  B obj2;
  obj2.disp();
  return 0;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-17 15:25:59

是函数覆盖运行时多态或编译时多态性。

您只能使用override虚拟方法来支持运行时多态性。如果所有事实在编译时都已知,那么聪明的编译器可能可以在没有vtables (用于虚拟调度)的情况下进行管理,但如果不知道,则必须在运行时解析。

让随机数生成器从不同的子类创建对象,并将它们传递给接受基类指针(或引用)的函数,该函数仍然能够调用对象的重写函数。这是在运行时解决的。隐藏基类函数或子类重载的函数将不可用。

一个例子(没有随机化):

代码语言:javascript
复制
#include <iostream>

class Foo {
public:
    void not_virtual() { std::cout << "not_virtual\n"; }
    virtual void func() = 0;

    virtual ~Foo() = 0;
};

Foo::~Foo() {}

void Foo::func() {
    std::cout << "default implementation\n";
}

class FooImpl : public Foo {
public:
    void not_virtual() {      // hiding - Foo's not_virtual()
        std::cout << "not_virtual, but in FooImpl\n";
    }
    void not_virtual(int x) { // overloading - same name, different signature
        std::cout << "not_virtual " << x << "\n";
    }
    void func() override { std::cout << "Impl\n"; }
};

void interface_user(Foo& x) { // slice away all but the Foo part of the object
                              // but
    x.func();                 // func() is in the vtable, call child class' function
    x.not_virtual();          // not in the vtable, call Foo's function
    // x.not_virtual(2);      // error: Foo doesn't have this overload
}

int main() {
    FooImpl f;

    f.func();          // calling overridden func
    f.not_virtual();   // calling function hiding the base class function
    f.not_virtual(1);  // calling overloaded func

    interface_user(f); // slicing - the function takes a Foo&
}

输出:

代码语言:javascript
复制
Impl
not_virtual, but in FooImpl
not_virtual 1
Impl
not_virtual
票数 0
EN

Stack Overflow用户

发布于 2019-10-17 13:41:56

只有虚拟函数调用在运行时被解析。如果函数是非虚拟的,如您的示例所示,调用将在编译时解析。

查看未优化的程序集(由gcc 9.2使用-O0生成),主要函数被编译为:

代码语言:javascript
复制
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        lea     rax, [rbp-1]
        mov     rdi, rax
        call    _ZN1A4dispEv
        lea     rax, [rbp-2]
        mov     rdi, rax
        call    _ZN1B4dispEv
        mov     eax, 0
        leave
        ret

奇怪的名称_ZN1A4dispEv_ZN1B4dispEv是名称损坏的结果:在这种情况下,编译器会为函数创建唯一的名称(请记住,在程序集中不存在oop)。实际的损坏是编译器定义的,但是您可以注意到类的名称(分别是AB )和函数disp的名称。

如果dispA中被声明为virtual,那么main应该如下所示:

代码语言:javascript
复制
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
->      mov     eax, OFFSET FLAT:vtable for A+16
->      mov     QWORD PTR [rbp-8], rax
        lea     rax, [rbp-8]
        mov     rdi, rax
        call    A::disp()
->      mov     eax, OFFSET FLAT:vtable for B+16
->      mov     QWORD PTR [rbp-16], rax
        lea     rax, [rbp-16]
        mov     rdi, rax
        call    B::disp()
        mov     eax, 0
        leave
        ret

标记为->的行是vtable查询,用于在运行时解析函数调用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58434089

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档