能力值:
( LV2,RANK:10 )
2 楼
Mase()
{
Base base;
PULONG_PTR Base_VTable =reinterpret_cast<PULONG_PTR>(dynamic_cast<Base*>(&base));
PULONG_PTR Mase_Base_VTable = reinterpret_cast<PULONG_PTR>(dynamic_cast<Base*>(this));
DWORD dwProtect;
VirtualProtect((PVOID)Mase_Base_VTable, sizeof(ULONG_PTR), PAGE_READWRITE, &dwProtect);
Mase_Base_VTable[0] = Base_VTable[0];
VirtualProtect((PVOID)Mase_Base_VTable, sizeof(ULONG_PTR), dwProtect, &dwProtect);
}
不要用 (int*)this获取虚函数表,虚函数表不是一定在第一个。(RTTI的影响等)
不要用Base::fun获取类成员指针,因为得到的是一个thunk。
--------------------------------------------------------------------------------------
知道C++内存布局是好事,不过尽量不要硬编码引用C++编译器生产的数据,不同的编译器会有差异的。
能力值:
( LV6,RANK:80 )
3 楼
看了您的代码跟建议还是很有收获的,非常感谢指点.自己写的代码灵活性实在太差了.
我这边写的:
Mase()
{
//需要修改派生类的vptr用Base::fun替换掉
int **x=(int**)*( (int*)this+2);
typedef void (Base::*Funx)(void);
Funx temp;
Base base;
temp=**(Funx**)(&base);
//temp=&Base::fun;//得到基类fun函数的地址是个thunk
DWORD nOld=0;
VirtualProtect(x,sizeof(x),PAGE_READWRITE,&nOld);
int error=GetLastError();
*x=(int*)*(int**)&temp;//覆盖掉派生类对象中基类vptr的第一项用基类fun函数地址替换Mase:fun
VirtualProtect(x,sizeof(x),nOld,&nOld);
} 见笑了.
能力值:
( LV2,RANK:10 )
4 楼
不错,学习了,理解c++更深刻了~
能力值:
( LV3,RANK:20 )
5 楼
请问这东西有神马实用价值?搞不明白。
能力值:
( LV15,RANK:520 )
6 楼
这个不就是高效C++55个做法中讲的构造函数内不能调用基类的虚函数的那一段吗,派生类的函数把基类的虚函数给覆盖了,名词覆盖。
能力值:
( LV15,RANK:520 )
7 楼
楼主是科锐的吧?????????
能力值:
( LV15,RANK:520 )
8 楼
百度一份答案来:
class A { public: A(int sss = 0):x(sss) { } virtual void Show() { cout << x << endl; } private: int x; }; class B : public A { public: B(int s):A(s),y(s){} void Show() { //A::Show 想在这里调用基类的Show cout << y << endl; } private: int y; }; int main() { B s(0); B s1(1); s.Show(); s1.Show(); _getch(); return 0; }
能力值:
( LV15,RANK:440 )
9 楼
重新温习了下C++,感觉收获了不少。
楼上有人改写虚函数表,然而虚函数表是由编译器分配在不可写的内存区域,要改必须调用系统函数(题目应该没让你#include<windows.h>吧?),这和打内存补丁没什么区别了。。。。。。。。而我们的类对象却是分配在可写的内存区的,改它的内容是可能的。所以我试了试直接改类对象的虚函数表指针。代码如下:
class Base
{
public:
virtual void fun()
{
printf("Base\n");
}
};
class Mase:virtual public Base //这个虚继承很关键!,因为本类中无新的虚函数,所以this处是VBT
{
public:
Mase()
{
int *vbtptr = *(int **)this;//注意,不是VFT
Base *p = new Base();//提取一个基类的虚函数表指针
*(int*)(vbtptr[1] +(int)this) = *(int*)p;//替换当前类继续的基类虚函数表指针
}
void fun()
{
printf("Mase\n");
}
void add()
{
printf("add\n");
}
};
int main()
{
Base *p1=new Mase;
p1->fun();
delete p1;
return 0;
}
能力值:
( LV6,RANK:80 )
10 楼
其实重点不是这个,小弟我也不是科锐的。。。。不过,小道消息:出此题的人是科锐的,哈哈
能力值:
( LV6,RANK:80 )
11 楼
楼主的思路清晰,小弟佩服了。其实题目没说不让修改内存属性(包含windows.h),给力!
能力值:
( LV6,RANK:90 )
12 楼
个人认为 此题的目的是让你搞清楚 什么时候建立虚表的,接着来个理论联系实际而已,证明你的猜想是正确的
能力值:
( LV15,RANK:520 )
13 楼
输出:
Base
Mase
答案(麻烦打下分数):
#include <stdio.h> class Base { public: virtual void fun() { printf("Base\n"); } }; class Mase:virtual public Base { public: Mase() { Base::fun(); } void fun() { printf("Mase\n"); } void add() { printf("add\n"); } }; int main() { Base *p1=new Mase; p1->fun(); delete p1; return 0; }
能力值:
( LV15,RANK:440 )
14 楼
要求如下: 通过给Mase添加构造函数实现让程序函数调用都输出Base。
可能是做卷思维定式了。如果空只给留在这个函数里,其它地方不让动,#include是不能在这儿用的.........
能力值:
( LV2,RANK:10 )
15 楼
潜力贴留名.Opera插图补丁.颜色补丁.字数补丁..
能力值:
( LV6,RANK:80 )
16 楼
[QUOTE=邓韬;1118633]输出:
Base
Mase
答案(麻烦打下分数):[/QUOTE]
怪我没有描述清楚吧。不是你的这个意思,你这个输出了2个结果,一次调用了基类的fun,一次调用了派生类的fun,这个题目的意思通俗点讲就是:如何阻止多态?方法基本上就是上面的2种:可以修改虚表指针vptr,也可以修改虚表中vtbl的内容,用基类的覆盖掉派生类的。