#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class A{
protected:
virtual void fun(){
printf("class:a function:fun\n");
}
virtual void fun2(){
printf("class:a function:fun2\n");
}
};
class B:public A{
protected:
void fun(){
printf("class:b function:fun\n");
}
void fun2(){
printf("class:b function:fun2\n");
}
};
int main(){
//输入和输出重定向
freopen("in.txt","r", stdin);
freopen("out.txt", "w", stdout);
void (*fun)(A*);
A* pa = new B();
long fp;
memcpy(&fp, pa, 4);
memcpy(&fun, reinterpret_cast<long*>(fp), 4);
fun(pa);
memcpy(&fun, reinterpret_cast<long*>(fp)+1, 4);
fun(pa);
delete pa;
return 0;
}
输出结果如下:
class:b function:fun
class:b function:fun2
百度百科的解释:
void (*fun)(A*); 这段定义了一个
函数指针名字叫做fun,而且有一个A*类型的参数,这个函数指针待会儿用来保存从vtbl里取出的函数地址
A* p=new B(); new B是向内存(内存分5个区:全局名字空间,自由存储区,寄存器,代码空间,栈)自由存储区申请一个内存单元的地址然后隐式地保存在一个
指针中.然后把这个地址赋值给A类型的指针P.
.
long fp; 这个long类型的
变量待会儿用来保存vptr的值
memcpy(&fp,pa,4); 前面说了,他们的实例对象里只有vptr
指针,所以我们就放心大胆地把pa所指的4bytes内存里的东西复制到fp中,所以复制出来的4bytes内容就是vptr的值,即vtbl的地址
现在有了vtbl的地址了,那么我们现在就取出vtbl第一个slot里的内容
memcpy(&fun, reinterpret_cast<long*>(fp), 4); 取出vtbl第一个slot里的内容,并存放在
函数指针fun里。需要注意的是fp里面是vtbl的地址,但fp不是
指针,所以我们要把它先转变成指针类型
fun(pa); 这里就调用了刚才取出的函数地址里的函数,也就是调用了B::fun()这个函数,也许你发现了为什么会有参数p,其实类
成员函数调用时,会有个this
指针,这个p就是那个this指针,只是在一般的调用中
编译器自动帮你处理了而已,而在这里则需要自己处理
分享到:
相关推荐
3. **虚函数调用**:虚函数允许在派生类中重写基类的函数,从而实现多态性。通过基类指针或引用调用时,会根据实际指向的对象类型动态决定调用哪个版本的函数。 4. **构造函数与析构函数调用**:构造函数用于初始化...
本文旨在探讨C++中的虚函数调用机制,通过分析一个简单的示例程序,解释虚函数如何在运行时被正确地调用,并深入剖析这一过程背后的原理。 #### C++中的虚函数调用机制 C++中的虚函数调用机制主要依赖于虚拟表...
在上面的代码中,虽然没有直接展示虚函数表,但其工作原理如下:`base_class`、`drived_class1`和`drived_class2`每个类都有自己的vtable,`pbc`指向不同对象时,调用虚函数实际上是在访问相应的vtable并执行相应的...
虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数,而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。...
3. 如果类有派生类,并且派生类也定义了虚函数,那么编译器会在派生类的虚函数表中添加派生类特有的虚函数,并在派生类构造函数执行完毕后,更新 `vptr` 以指向派生类的虚函数表。 4. 当通过基类指针调用虚函数时,...
这就涉及到了在派生类的构造函数中调用基类构造函数的知识点。 首先,每个类都有一个构造函数,它在对象创建时自动执行,用于初始化类的数据成员。当派生类创建时,它的构造函数会先于派生类的任何其他操作调用基类...
因此,如果在构造函数中调用虚函数,程序可能会错误地认为对象是基类类型,而不是实际的派生类类型,从而导致错误的结果。 同样,在析构过程中,一旦派生类的析构函数开始执行,对象的派生类数据成员就被认为是...
在类继承层次中,如果基类的虚函数在派生类中被重定义(覆盖),那么派生类的VTABLE将会包含它自己版本的虚函数地址,而基类的VTABLE仍然保留原有的地址。这保证了不论对象实际属于哪个类,调用虚函数都会执行相应类...
在C++编程中,类之间的相互调用是一个常见的设计模式,尤其在实现复杂系统或对象间的协作时。这种设计允许类A访问类B的成员,同时类B也可以访问类A的成员,形成一种循环依赖的关系。然而,这种关系需要谨慎处理,以...
总结来说,这个测试用例主要关注虚函数在C++中的作用,包括多态性、动态绑定、抽象类和接口设计、资源管理以及虚函数表的工作原理。通过一系列的例子和测试,我们可以深入理解虚函数如何提升代码的灵活性和可扩展性...
在C++中,虚函数的主要作用是实现多态性,即允许父类型的指针或引用调用子类重写的成员函数。这种机制使得程序员能够编写更灵活、可扩展的代码。例如: ```cpp class Base { public: virtual void func() { cout ;...
remote-function支持调用普通函数,也支持调用类的成员函数。 remote-function底层使用命令管道进行通讯,内置的流程完成了函数参数和返回值的序列化过程。且大部分的参数和返回值都可以使用内置的(反)序列化方法...
当一个函数在基类中声明为虚函数时,子类可以重写这个函数,并且在运行时,通过基类指针或引用调用该函数时,会根据实际对象的类型调用相应的实现,这就是动态绑定或运行时多态。虚函数的这种特性使得虚函数在很多...
它允许我们使用基类类型的指针或者引用指向派生类的对象,从而在运行时决定调用哪个方法。这种灵活性的核心在于虚函数及其虚函数表。 假设我们有一个基类`ClassA`和一个继承自`ClassA`的派生类`ClassB`,并且`...
构造函数:不可以虚化(重写),在子类的构造函数前自动被调用一次父类的构造函数. 析构函数:当[DELETE]类指针时 非虚会从[此类]一直释放到基类,为虚时会从被赋于的[NEW类]的析构函数一直释放到基类. 总得来说释放[方向...
在销毁对象时,如果对象是通过基类指针或引用删除的,而对象实际上是派生类的实例,那么非虚析构函数只会调用基类的析构函数,派生类的析构函数不会被调用,可能会导致内存泄漏或资源未释放的问题。虚析构函数则能...
每个包含虚函数的类实例都会在内存中分配一个虚函数表的指针,通常位于实例内存的最前面,以提高访问效率。当使用父类指针调用虚函数时,实际上是通过这个指针找到虚函数表,然后根据表中的地址调用实际的函数实现。...
3. 如果类有继承关系,子类的虚函数表会包含父类的虚函数表,并在其后添加新的、重写的或新增的虚函数指针。 在C++中,我们可以利用`dynamic_cast`等类型转换操作符,配合虚函数表来实现运行时类型检查。例如,当...
spring与java反射结合动态定义类及调用函数,实现类的动态定义和函数的动态调用。 为有动态调用的web应用提供一点点借鉴,相互学习。