在本Lab中,你需要在类作用域外访问类中的私有成员变量和私有成员函数,在这个Lab中你会应用C++类布局相关知识。
更新LabEnv,更新docker环境。请参考Lab1 B部分 第8小节内容
检查docker container是否正常运行
sudo docker start pore_image
启动docker容器
sudo docker exec -it pore_image bash
进入docker容器
进入虚拟机中对应路径cd ~/pore24/pore_XXXXX
,其中pore_XXXXX
需替换为pore_自己学号
使用git指令git pull origin master
拉取本Lab的题目环境,或参考Lab1。git仓库目录应包含release_lab2,目录结构如下
release_lab2
└── source.cpp
// 在C++中定义函数指针
// 定义func为函数指针类型,其参数为(int, double),返回值类型为int
typedef int(*func)(int, double);
// 使用强制类型转换转换为函数指针类型
func f = (func)xxx;
// 调用函数指针,与正常函数指针调用一致
int result = f(1, 0.0);
// 在C++中可以使用基值+偏移来访问数据
int a[100] = {0};
a[15] = 100;
// 例如访问a[15],其相对于a[0]的偏移为15 * sizeof(int)
// 则a[15]的地址为(void*)&a[0] + 15 * sizeof(int)
// 将该指针类型转换为int*,取内容即可得到a[15]的值
int x = *(int*)((void*)&a[0] + 15 * sizeof(int));
// 输出为100 100
printf("%d %d\n", x, a[15]);
进入docker container,sudo docker exec -it pore_image bash
启动qemu虚拟机,./start_vm.sh
新开一个终端,使用ssh连接qemu虚拟机,命令为ssh pore@localhost -p 6666
,pore账户的密码为pore
在Linux虚拟机(MacOS/Linux用户使用物理机)中使用C/C++编写hello world程序,将hello_world.cpp复制到qemu虚拟机中,编译后的二进制文件能够正确输出Hello World!
示例步骤如下:
# song@song-virtual-machine:~/pore24
# 1. 在虚拟机/MacOS/Linux主机中创建hello_world.cpp,并编写hello world代码
# song@song-virtual-machine:~/pore24/LabEnv
# 2. 使用LabEnv中cp_to_qemu.sh将hello_world.cpp传输到qemu虚拟机中
./cp_to_qemu.sh ../hello_world.cpp
# 3. 使用g++编译cpp代码
g++ hello_world.cpp -o hello_world
# 4. 运行hello_world二进制程序,输出 Hello World!
# pore@localhost:~
./hello_world
使用pore
用户登陆qemu虚拟机,编写HelloWorld程序,将HelloWorld程序截图放到report.docx
中(10分)
将在qemu虚拟机中执行二进制文件的输出截图放到report.docx
中(10分)
本任务要求在source.cpp
中指定位置填写代码,在虚拟机中编译并运行,输出class A
中私有变量x
的值,class A
成员变量的布局如下图所示。
注意: 为了避免抄袭,下发到每个同学的source.cpp
中class A
的结构并不相同,请同学们仔细阅读自己的代码。
class A {
public:
explicit A(int x) {
this->x = x;
}
private:
long long var_ivyLMpevQn;
short var_CFeXdNbYeH;
long long var_WpNAZaQlGp;
short var_yBOzRcicFa;
long long var_gOOPdhjyZT;
int var_JkQEaxdsta;
long long var_bSFxbzAwgw;
long long var_QaJrZhiqGP;
short var_jMyWTuOcRA;
long long var_NVLaONDQHI;
// 需要访问的变量
int x;
int var_GLcewzGkDP;
short var_eHbKxYIHfT;
short var_cZikCpZBNK;
int var_tUvmAqbXBX;
char var_BJLYjhyIUV;
short var_jpVZzXEMNq;
int var_SvjCyJCRFR;
long long var_pCEKFmTpvr;
char var_vdZSCsmAiJ;
short var_jpRfQRnRtx;
...
};
在task2、task3中,所有代码均在main函数中编写,请注意不要修改main函数前两行初始化内容。
int main(int argc, const char** argv) {
int passwd = std::stoi(argv[1]);
A a(passwd);
// Lab2 访问x变量的值
// Write your code here...
// End of your code
return 0;
}
在main函数中完成填写之后,应该达到如下效果:
在report.docx
中说明class A
的内存布局,需包括每个成员变量在结构体内的偏移,并说明计算过程(20分)
在source.cpp
的指定位置按照要求填写代码,提交source.cpp
(10分)
本任务要求在source.cpp
中指定位置填写代码,在虚拟机中编译并运行,调用class A
中私有成员函数getX
,并将其值输出到命令行,class A
成员函数的布局如下图所示。
class A {
public:
explicit A(int x) {
this->x = x;
}
private:
...
virtual int func_RoaCuOLRsg() { return x + 37; }
virtual int func_CbYSCqggPs() { return x + 37; }
virtual int func_auEenPaLGP() { return x + 1; }
int func_xkJchTsfzh() { return x + 4; }
int func_WvyefKIkMX() { return x + 46; }
int func_tLDSVLAEAZ() { return x + 9; }
virtual int func_HawVPAxPwU() { return x + 22; }
int func_BbWEnymJCb() { return x + 17; }
virtual int func_pegJDDsEeW() { return x + 10; }
virtual int func_yMEoHSVGZr() { return x + 46; }
// 需要调用的函数
virtual int getX() { return x + 1; }
virtual int func_NqOaBvpcUh() { return x + 10; }
virtual int func_wJXmJDnLPZ() { return x + 44; }
virtual int func_qXgYzQMODg() { return x + 6; }
virtual int func_QzqCvTmRbp() { return x + 1; }
virtual int func_FpmHEJTYYr() { return x + 26; }
int func_xMJbXNchuG() { return x + 42; }
int func_PgcBmUpaWa() { return x + 12; }
virtual int func_aGSHfwINrO() { return x + 34; }
virtual int func_UIlVcjSlNK() { return x + 23; }
int func_XrSYAbIjLT() { return x + 18; }
};
注意: 题目中getX
成员函数一定是虚函数
在main函数中完成填写之后,应该达到如下效果:
在report.docx
中解析调用私有函数getX
的原理(如果使用到偏移,需写明偏移如何计算得出)(30分)
在source.cpp
的指定位置填写代码,提交source.cpp
(20分)
提交前请检查你的文件结构是否如下所示:
注意:report.docx
应该包含task1,task2,task3的所有文档
请在report.docx
中尽可能详细的讲述实验思路,即使没有成功的代码实现,助教组也会根据思路酌情给分
lab2/
├── report.docx
├── task2
│ └── source.cpp
└── task3
└── source.cpp