c++ 中的方法覆盖:是编译时间还是 运行 时间多态性?
Method overriding in c++ : is it compile time or run time polymorphism?
在 C++ 中,函数重写 运行 时间多态性还是编译时多态性? 我认为这是编译时多态性,因为调用适当的每个信息都需要函数很早就为编译器所知。在下面的代码中,obj.disp();
这里编译器知道 obj 是 base class 的对象,所以它会立即解析对 base class 的 disp()
函数的调用。对于 obj2.disp();
也是如此 这里编译器知道 obj2 是派生 class 的对象,因此它将调用派生 class 的 disp() 函数。我不明白为什么它被称为运行-time polymorphism.
还是JAVA,人们把函数重载称为运行时间多态。请解释一下....
#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;
}
只有虚函数调用在运行时解析。如果函数是非虚拟的,如您的示例所示,则调用在编译时解析。
查看未优化的程序集(由 gcc 9.2 使用 -O0 生成),主要函数被编译为:
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) .实际的 mangling 是编译器定义的,但您可以注意到 class 的名称(分别为 A
和 B
)和函数名称 disp
.
如果 disp
在 A
中被声明为 virtual
,那么 main
看起来像:
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查询,用于在运行时解析函数调用。
Is function overriding run time polymorphism or compile time polymorphism
您只能使用 override
虚方法,并且这些方法支持 运行 时间多态性。如果在编译期间知道所有事实,那么聪明的编译器可能无需 vtables
(用于虚拟分派)就可以管理,但如果不是,则必须在 运行 时间内解决。
让随机数生成器从不同的子 classes 创建对象并将它们传递给接受基 class 指针(或引用)的函数,并且该函数仍然能够调用对象的重写函数。这在 运行 时间内解决了。隐藏基 class 函数或子 class 重载的函数将不可用。
一个例子(没有随机化):
#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&
}
输出:
Impl
not_virtual, but in FooImpl
not_virtual 1
Impl
not_virtual
在 C++ 中,函数重写 运行 时间多态性还是编译时多态性? 我认为这是编译时多态性,因为调用适当的每个信息都需要函数很早就为编译器所知。在下面的代码中,obj.disp();
这里编译器知道 obj 是 base class 的对象,所以它会立即解析对 base class 的 disp()
函数的调用。对于 obj2.disp();
也是如此 这里编译器知道 obj2 是派生 class 的对象,因此它将调用派生 class 的 disp() 函数。我不明白为什么它被称为运行-time polymorphism.
还是JAVA,人们把函数重载称为运行时间多态。请解释一下....
#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;
}
只有虚函数调用在运行时解析。如果函数是非虚拟的,如您的示例所示,则调用在编译时解析。
查看未优化的程序集(由 gcc 9.2 使用 -O0 生成),主要函数被编译为:
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) .实际的 mangling 是编译器定义的,但您可以注意到 class 的名称(分别为 A
和 B
)和函数名称 disp
.
如果 disp
在 A
中被声明为 virtual
,那么 main
看起来像:
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查询,用于在运行时解析函数调用。
Is function overriding run time polymorphism or compile time polymorphism
您只能使用 override
虚方法,并且这些方法支持 运行 时间多态性。如果在编译期间知道所有事实,那么聪明的编译器可能无需 vtables
(用于虚拟分派)就可以管理,但如果不是,则必须在 运行 时间内解决。
让随机数生成器从不同的子 classes 创建对象并将它们传递给接受基 class 指针(或引用)的函数,并且该函数仍然能够调用对象的重写函数。这在 运行 时间内解决了。隐藏基 class 函数或子 class 重载的函数将不可用。
一个例子(没有随机化):
#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&
}
输出:
Impl
not_virtual, but in FooImpl
not_virtual 1
Impl
not_virtual