首页
社区
课程
招聘
6
[分享]一道“简单”的c++题目(个人觉得还是要对c++对象模型有比较深刻的理解才行)
发表于: 2012-11-11 15:30 7930

[分享]一道“简单”的c++题目(个人觉得还是要对c++对象模型有比较深刻的理解才行)

2012-11-11 15:30
7930
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Base
{
public:
    virtual void fun()
    {
        printf("Base\n");
    }
};
class Mase:virtual public Base
{
public:
    void fun()
    {
        printf("Mase\n");
    }
    void add()
    {
        printf("add\n");
    }
};
 
int main()
{
    Base *p1=new Mase;
    p1->fun();
    delete p1;
    return 0;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 6
支持
分享
赞赏记录
参与人
雪币
留言
时间
伟叔叔
为你点赞~
2024-5-31 06:19
心游尘世外
为你点赞~
2024-5-31 03:12
QinBeast
为你点赞~
2024-5-31 03:04
飘零丶
为你点赞~
2024-4-1 00:29
shinratensei
为你点赞~
2024-2-2 03:05
PLEBFE
为你点赞~
2023-3-7 00:38
最新回复 (15)
雪    币: 14
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    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++编译器生产的数据,不同的编译器会有差异的。
2012-11-11 17:58
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
看了您的代码跟建议还是很有收获的,非常感谢指点.自己写的代码灵活性实在太差了.
我这边写的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
}
见笑了.
2012-11-12 09:21
0
雪    币: 1358
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不错,学习了,理解c++更深刻了~
2012-11-16 17:00
0
雪    币: 326
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
请问这东西有神马实用价值?搞不明白。
2012-11-16 17:05
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
6
这个不就是高效C++55个做法中讲的构造函数内不能调用基类的虚函数的那一段吗,派生类的函数把基类的虚函数给覆盖了,名词覆盖。
2012-11-16 17:06
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
7
楼主是科锐的吧?????????
2012-11-16 17:09
0
雪    币: 278
活跃值: (709)
能力值: ( 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;
}
2012-11-16 17:16
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
9
重新温习了下C++,感觉收获了不少。

楼上有人改写虚函数表,然而虚函数表是由编译器分配在不可写的内存区域,要改必须调用系统函数(题目应该没让你#include<windows.h>吧?),这和打内存补丁没什么区别了。。。。。。。。而我们的类对象却是分配在可写的内存区的,改它的内容是可能的。所以我试了试直接改类对象的虚函数表指针。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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;
}
2012-11-17 14:08
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
10
其实重点不是这个,小弟我也不是科锐的。。。。不过,小道消息:出此题的人是科锐的,哈哈
2012-11-17 16:19
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
11
楼主的思路清晰,小弟佩服了。其实题目没说不让修改内存属性(包含windows.h),给力!
2012-11-17 16:21
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
12
个人认为 此题的目的是让你搞清楚 什么时候建立虚表的,接着来个理论联系实际而已,证明你的猜想是正确的
2012-11-17 16:43
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
13
输出:
1
2
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;
}
2012-11-17 16:58
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
14
要求如下:
通过给Mase添加构造函数实现让程序函数调用都输出Base。


可能是做卷思维定式了。如果空只给留在这个函数里,其它地方不让动,#include是不能在这儿用的.........
2012-11-17 17:38
0
雪    币: 90
活跃值: (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
潜力贴留名.Opera插图补丁.颜色补丁.字数补丁..
2012-11-17 19:44
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
16
[QUOTE=邓韬;1118633]输出:
1
2
Base
Mase

答案(麻烦打下分数):[/QUOTE]

怪我没有描述清楚吧。不是你的这个意思,你这个输出了2个结果,一次调用了基类的fun,一次调用了派生类的fun,这个题目的意思通俗点讲就是:如何阻止多态?方法基本上就是上面的2种:可以修改虚表指针vptr,也可以修改虚表中vtbl的内容,用基类的覆盖掉派生类的。
2012-11-18 00:12
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册