从继承函数中调用虚拟函数
Calling a virtual function from within an inherited function?
我试着在脑子里想清楚,但老实说,我不知道这里到底发生了什么
在下面的示例中添加和删除虚拟关键字时,到底发生了什么?
#include <iostream>
#include <string>
class A {
public:
A() { me = "From A"; }
void caller() { func(); }
virtual void func() { std::cout << me << std::endl; } // THIS LINE!
private:
std::string me;
};
class B : public A {
public:
B() { me = "From B"; }
void func() { std::cout << me << std::endl; }
private:
std::string me;
};
int main() {
A a;
a.caller();
B b;
b.caller();
return 0;
}
使用虚拟关键字,它会打印"来自A",然后打印"来自B"
在没有虚拟关键字的情况下,它会打印"From A",然后是"From"
到目前为止,这是我唯一一次发现在不涉及指针的情况下使用虚拟函数。我认为,如果删除虚拟关键字,编译器会做标准的事情,即重载继承的函数,最终打印"From A"answers"From B"
我认为这不仅仅是VTable,更重要的是它在特定情况下的行为方式。B有VTable吗?
调用
func()
相当于
this->func()
因此,包含一个指针。
不过,没有必要涉及指针来理解行为。
当func
在静态已知类型中是虚拟的时,即使是b.func()
的直接调用也必须工作,就好像是虚拟调用一样。编译器可以在知道b
的最派生类型的基础上对其进行优化。但这是另一种考虑(优化几乎可以做任何事情)。
除了虚拟调度的问题之外,可能带来额外混乱的是您有两个me
,一个在A
中声明,另一个在B
中声明。这是两个不同的对象。
CCD_ 7类型的对象具有两个CCD_ 8类型的数据成员;一个单独存在,一个合并到类型为A
的子对象中。然而,后一个在类型为B
的方法中并不立即可用,因为它的名称被该类中引入的新me
所掩盖(尽管您可以使用限定名称A::me
来指代它)。
因此,即使A::func
和B::func
的主体看起来相同,但在它们两者中使用的标识符me
指代不同的成员。
在您的示例中,您不会看到区别:
-
使用虚拟函数,编译器将通过VTable生成一个调用,在运行时,每个对象都将为其真实类调用正确的函数。
-
对于非虚拟函数,编译器在编译时根据对象定义的类确定要调用的正确函数。
现在尝试以下操作,查看虚拟功能的作用:
A *pa = &b; // pointer to an A: valid as b is a B wich is also an A.
pa -> caller(); // guess what will be called if virtual or not.
不需要指针来尝试虚拟函数。你也可以在参考文献中观察到同样的效果:
A& ra = b; // create a reference to an A, but could as well be a parameter passed by reference.
ra.caller();
虚拟函数对多态性很有用。这个想法是,你使用一个类的通用对象,但在编译时你不知道这个对象在运行时是否真的属于这个类,或者它是否不是一个更专业化的对象(从类继承)。
- C++无法定义虚拟函数 OUTER 类和头文件
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 尝试将unique_ptrs推送到向量时使用纯虚拟函数错误
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 当覆盖存在时调用基本虚拟"binded to object"函数
- 如何在C++中伪造虚拟可变参数函数模板?
- 类型擦除的std::function与虚拟函数调用的开销
- 重写虚拟函数和继承
- 是否可以使用函数指针调用虚拟析构函数?
- 在没有动态内存的世界中,我是否需要虚拟析构函数?
- 虚拟继承基构造函数消除
- "虚拟""覆盖"析构函数
- 类中的虚拟布尔函数参数不起作用
- 用纯虚拟函数兜圈子
- 将C++子类成员函数(虚拟实现)传递给 C 类型函数指针
- 尝试在 QLabel 上绘画失败(无法在没有对象的情况下调用成员函数"虚拟无效 QLabel::p aintEvent(QPaintEvent*)")
- 声明析构函数虚拟就足够了吗?
- 视觉 C++当我们在基类中使函数成为纯虚拟时,那么在子类中再次使相同的函数虚拟的必要性是什么
- 重载函数(虚拟/非虚拟)