使用虚拟功能的强大功能
考虑以下示例代码:
class Base {
public:
void f();
virtual void vf();
};
class Derived : public Base {
public:
void f();
void vf();
};
#include <iostream>
using namespace std;
void Base::f() {
cout << "Base f()" << endl;
}
void Base::vf() {
cout << "Base vf()" << endl;
}
void Derived::f() {
cout << "Derived f()" << endl;
}
void Derived::vf() {
cout << "Derived vf()" << endl;
}
int main()
{
Base b1;
Derived d1;
b1.f();
b1.vf();
d1.f();
d1.vf();
Derived d2; // Derived object
Base* bp = &d2; // Base pointer to Derived object
bp->f(); // Base f()
bp->vf(); // which vf()?
return 0;
}
运行的输出为:
Base f()
Base vf()
Derived f()
Derived vf()
Base f()
Derived vf()
问题:
在
Base* bp = &d2
行中,对象类型在编译时已知。那么在bp->vf();
的情况下使用哪个函数也可以在编译时决定,对吗?由于对象类型在编译时本身已知,因此该示例程序中是否使用了虚拟函数的强大功能?
Consider the following sample code:
class Base {
public:
void f();
virtual void vf();
};
class Derived : public Base {
public:
void f();
void vf();
};
#include <iostream>
using namespace std;
void Base::f() {
cout << "Base f()" << endl;
}
void Base::vf() {
cout << "Base vf()" << endl;
}
void Derived::f() {
cout << "Derived f()" << endl;
}
void Derived::vf() {
cout << "Derived vf()" << endl;
}
int main()
{
Base b1;
Derived d1;
b1.f();
b1.vf();
d1.f();
d1.vf();
Derived d2; // Derived object
Base* bp = &d2; // Base pointer to Derived object
bp->f(); // Base f()
bp->vf(); // which vf()?
return 0;
}
The output of the run is:
Base f()
Base vf()
Derived f()
Derived vf()
Base f()
Derived vf()
Questions:
In the line
Base* bp = &d2
, the object type is known at compile time. Then the decision of which function to use in the case ofbp->vf();
can also be made at compile time right?Since the object type is known at compile time itself, is the power of virtual functions used in this sample program?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的。
这是大多数现代智能编译器都能够做到的编译器优化的一部分。
如果编译器可以在编译时自行确定要调用哪个函数,那么它就会这样做。虽然这完全取决于编译器是否可以检测到在编译时或运行时调用的确切函数,但虚拟主义可以保证您的程序具有您想要的行为。
完全取决于编译器。大多数现代编译器将能够在编译时评估此函数调用。
Yes.
This is a part of compiler optimization which most modern day smart compilers will be able to do.
If an compiler can determine which function to call at compile time itself then it will do so. While this entirely depends on the compiler whether it can detect the exact function to call at compile time or run time, virtualism guarantees you the behavior you want for your program.
Depends entirely on the compiler. Most modern day compilers will be able to evaluate this function call at compile time.
这个程序很简单,并且确实没有很好地展示虚拟函数(或更普遍的多态性)的强大功能。考虑这个变化:
这里,类的选择取决于用户输入 - 编译器无法预测当调用
ptr-> 时,
已达到。ptr
将实际指向什么类型的对象。 vf();This program is trivial, and does indeed not demonstrate the power of virtual functions (or, more generally polymorphism) very well. Consider this change:
Here, the choice of the class depends on user-input - the compiler has no way to predict what type of object
ptr
will actually point to when the callptr->vf();
is reached.嗯......这两个问题的“是”和“否”:这取决于您所争论的抽象级别。
从语言的角度来看,1) 是一种误解。
d2
的类型是已知的,但是当将 d2 地址分配给bp
时,从Derived*
到Base 的转换*
将会发生。从那时起,bp 的静态类型是
Base*
(因为这是它的声明),它指向其 Derived 的动态类型(因为这是运行时类型信息与对象关联的类型)指)。从他们开始,通过 bp 的每个操作都假定 Base* 作为一种类型,并且需要对每个虚拟函数进行重定向。
从编译器的角度来看,可以进行某些优化,并且由于在所有函数中,pb 始终指向 Derived,因此实际上可以跳过虚拟重定向。
但这是由于您的特定示例的结构方式所致,而不是因为语言功能。
Well... YES and NO to both questions: it depends on what abstraction level you are arguing.
By a language standpoint, 1) is a misconception. The type for
d2
is known, but when it comes d2 address to be assigned tobp
, a conversion fromDerived*
intoBase*
will happen.From tham on, the static type of bp is
Base*
(because that is its declaration) and the dynamic type it points to its Derived (because that's is what the run-time type information associate to the object refers to).From them on, every operation through bp assume Base* as a type, and requires a redirection for every virtual function.
By a compiler stand point, certain optimization can be done, and since in all your function your pb always points to a Derived, the virtual redirection can -in fact- be skipped.
But that's due to the way your particular example is structured, not because of a language feature.
在 Base* bp = &d2 行中,对象类型在编译时已知。然后在bp->vf()的情况下决定使用哪个函数;也可以在编译时进行,对吧?
不,要使用哪个函数的决定是在运行时根据对象的类型动态完成的,而不是根据该对象的指针/引用的类型。这称为动态绑定。编译器保留一个称为虚拟指针或 vptr 的隐藏指针,它指向一个称为虚拟表的表。每个类将有一个虚拟表,并且至少有一个虚拟函数(无论为该类创建了多少个对象)。虚表包含类的虚函数的地址。
既然对象类型在编译时本身就已知,那么这个示例程序中是否使用了虚函数的强大功能?
事实上,所指向的对象在编译时可能是未知的。以采用基类指针作为参数的方法为例,如下所示:
在这种情况下,实际对象可能是从
Shape
派生的任何形状。但绘制的形状取决于传入对象的实际类型。In the line Base* bp = &d2, the object type is known at compile time. Then the decision of which function to use in the case of bp->vf(); can also be made at compile time right?
No, the decision to which function to use is done dynamically at run-time based on the type of the object, not the type of pointer/reference to that object. This is called dynamic binding. Compiler keeps a hidden pointer called
virtual pointer
orvptr
which points to a table called virutal table. There would be one virtual table per class with atleast one virtual function (irrespective of how many objects created for the class). The virtual table contains address of the virtual functions of the class.Since the object type is known at compile time itself, is the power of virtual functions used in this sample program?
Infact the object pointed to might not be known at compile time. Take an example of a method which takes the base class pointer as the parameter as shown below:
In this case, the actual object might be any shape derived from
Shape
. But the shape drawn depends on the actual type of the object passed in.