`

在类的外面调用类保护类型的虚函数

    博客分类:
  • C++
 
阅读更多

 

#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指针,只是在一般的调用中编译器自动帮你处理了而已,而在这里则需要自己处理

 

 

分享到:
评论

相关推荐

    c++中子类对象不能调用父类中的虚函数

    然而,这里有一个陷阱:如果通过子类对象直接调用父类的虚函数,编译器会认为是在调用子类自身的实现,即使子类没有覆盖这个虚函数。这就是“子类对象不能调用父类中的虚函数”的含义。例如,假设我们有以下代码: ...

    C++箴言:避免析构函数调用虚函数

    1. **动态类型与静态类型不匹配**:在析构函数中调用虚函数时,C++使用的是静态绑定,即根据对象的静态类型(即编译时已知的类型)来决定调用哪个函数版本,而不是动态类型(即运行时的实际类型)。因此,即使你期望...

    C++中的类中函数调用

    3. **虚函数调用**:虚函数允许在派生类中重写基类的函数,从而实现多态性。通过基类指针或引用调用时,会根据实际指向的对象类型动态决定调用哪个版本的函数。 4. **构造函数与析构函数调用**:构造函数用于初始化...

    C++虚函数调用机制初探

    本文旨在探讨C++中的虚函数调用机制,通过分析一个简单的示例程序,解释虚函数如何在运行时被正确地调用,并深入剖析这一过程背后的原理。 #### C++中的虚函数调用机制 C++中的虚函数调用机制主要依赖于虚拟表...

    直接调用类成员函数地址

    在C++中,成员函数的指针是个...但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法。C++专门为成员指针准备了三个运算符: "::*"用于指针的声明,而"-&gt;*"和".*"用来调用指针指向的函数。

    虚函数表解析

    当通过基类的指针或者引用调用一个虚函数时,编译器会首先通过对象指针找到对应的虚函数表,然后根据调用的虚函数名在虚函数表中查找对应的函数地址,进而调用正确的函数实现。 #### 三、虚函数表的结构与实现 虚...

    构造函数不能声明为虚函数,析构函数可以声明为虚函数

    1. **避免内存泄漏**:如果基类指针指向派生类对象,并且基类的析构函数不是虚函数,那么通过基类指针删除派生类对象时,只会调用基类的析构函数。这样就会导致派生类中额外分配的资源没有得到释放,从而引发内存...

    C++虚函数实现原理

    通过虚函数,可以在基类中定义一个接口,并由派生类来具体实现该接口的功能,进而允许在运行时根据对象的实际类型动态调用正确的函数实现。本文将基于提供的示例代码,深入探讨虚函数的内部实现机制,特别是虚函数表...

    Delphi子类调用祖父类的虚函数.mht

    Delphi子类调用祖父类的虚函数.mht

    C++虚函数及虚函数表解析

    在上面的代码中,虽然没有直接展示虚函数表,但其工作原理如下:`base_class`、`drived_class1`和`drived_class2`每个类都有自己的vtable,`pbc`指向不同对象时,调用虚函数实际上是在访问相应的vtable并执行相应的...

    为什么构造函数不能是虚函数

    - 虚函数机制依赖于运行时类型识别(RTTI),这意味着在运行时才能确定实际调用的是哪个类的函数。 - 构造函数的主要任务是在对象创建时对其进行初始化,此时对象还未完全构建完成,其确切类型未知,因此无法有效地...

    C++ 虚函数表解析

    这样,当通过基类指针调用虚函数时,实际上调用的是派生类中对应的函数实现,即使是在运行时才确定对象的实际类型。 #### 虚函数表的实现 在C++标准中,编译器必须确保虚函数表的指针位于对象实例的最前面位置,以...

    C++箴言:避免析构函数调用虚函数[归类].pdf

    因此,如果在构造函数中调用虚函数,程序可能会错误地认为对象是基类类型,而不是实际的派生类类型,从而导致错误的结果。 同样,在析构过程中,一旦派生类的析构函数开始执行,对象的派生类数据成员就被认为是...

    C++中的虚函数表图解

    在C++中,虚函数是实现多态性的重要机制,多态是指使用父类型的指针或引用能够调用子类的成员函数,从而允许不同类型的对象以统一的方式进行处理。这种特性使得C++具备了泛型编程的能力,即用不变的代码解决可变的...

    虚函数的使用技巧.rar_C++虚函数_虚函数

    构造函数不能是虚函数,因为构造函数在对象创建时被调用,而此时虚函数表还未初始化。 7. **C++11的final关键字**: 从C++11开始,可以使用`final`关键字阻止子类进一步覆盖虚函数: ```cpp class Base { ...

    C++ 包含类两个类互相调用彼此的类成员变量和方法

    在C++编程中,类之间的相互调用是一个常见的设计模式,尤其在实现复杂系统或对象间的协作时。这种设计允许类A访问类B的成员,同时类B也可以访问类A的成员,形成一种循环依赖的关系。然而,这种关系需要谨慎处理,以...

    虚函数虚表的详解,大家看看!

    虚函数使得可以通过基类指针或引用来调用派生类中的重定义函数,从而实现动态绑定。 首先,当一个类声明了一个或多个虚函数,系统就会为这个类创建一个虚函数表(Virtual Table,简称VTBL)。这个虚表包含类的所有...

    c++ 类的互相调用的方法

    在一个类的成员函数中,可以直接调用本类的其他成员函数,也可以通过对象或指针间接调用其他类的成员函数。例如,我们有`ClassA`和`ClassB`两个类,`ClassA`中有一个成员函数`funcA()`,`ClassB`中有一个成员函数`...

Global site tag (gtag.js) - Google Analytics