首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C++ Trick:不使用friend,怎么访问private成员变量?

C++ Trick:不使用friend,怎么访问private成员变量?

作者头像
果冻虾仁
发布于 2021-12-08 13:40:47
发布于 2021-12-08 13:40:47
1.5K0
举报
文章被收录于专栏:后台公论后台公论

想知道怎么不使用friend,访问private的成员变量?

有方法,但不鼓励……

方法一

代码语言:javascript
复制

#include <iostream>
using namespace std;
class Sensei {
public:
    Sensei(int h, int w, char c):height(h), weight(w), cup(c) {}
private:
    int height;
    int weight;
    char cup;
};

int main() {
    Sensei sensei(160, 80, 'B');
    int height = *(int*)&sensei;
    int weight = *((int*)&sensei + 1);
    char cup = *(char*)((int*)&sensei + 2);

    cout<<height<<endl;
    cout<<weight<<endl;
    cout<<cup<<endl;
}

当存在内存对齐的时候,这个代码未必有效。主要就是手撸的内存偏移就不准了。当然如果你知道你的编译器是怎么个对齐规则,你也可以继续用。比如我们调换cup和weight的顺序。

代码语言:javascript
复制
#include <iostream>
using namespace std;
class Sensei {
public:
    Sensei(int h, int w, char c):height(h), weight(w), cup(c) {}
private:
    int height;
    char cup;
    int weight;
};

int main() {
    Sensei sensei(160, 80, 'B');
    int height = *(int*)&sensei;
    char cup = *(char*)((int*)&sensei + 1);
    int weight = *((int*)&sensei + 2);
    cout<<height<<endl;
    cout<<weight<<endl;
    cout<<cup<<endl;
}

在我们机器上是4字节对齐的,所以虽然cup是char类型,但是会空余3个byte之后才是weight。

当然除了内存对齐,还有可能有虚函数,占用额外内存空间。不过你既然已经能看到这了,说明自己清楚内存布局的各种问题,自己手撸吧,不介绍了。本身这个文章也是不鼓励实际应用的,仅供延伸思路。

方法二

定义一个同样字段的类(主要是字段类型和顺序要相同)来强制类型转换。

代码语言:javascript
复制
#include <iostream>
using namespace std;
class Sensei {
public:
    Sensei(int h, int w, char c):height(h), weight(w), cup(c) {}
private:
    int height;
    char cup;
    int weight;
};

struct Actor {
    int height;
    char cup;
    int weight;
};
int main() {
    Sensei sensei(160, 80, 'B');

    Actor actor = *((Actor*)&sensei);
    // 或者
    //Actor actor = *(reinterpret_cast<Actor*>(&sensei));
    cout<<actor.height<<endl;
    cout<<actor.weight<<endl;
    cout<<actor.cup<<endl;
}

方法三

方法三,比较Trick了。但比前两种反而有使用场景。比如我们要做UT(单元测试)的时候,测试类的某些数据成员是private的,并且没提供对外set的方法。但我们想hack一些数据进去,做测试。这时候这个Sensei类的定义是在一个独立头文件中,比如sensei.h。我们在ut的的cpp或头文件中include它,这种情况都不需要像前面两种那样脱裤子放屁。

代码语言:javascript
复制
// sensei.h
class Sensei {
public:
    Sensei(int h, int w, char c):height(h), weight(w), cup(c) {}
private:
    int height;
    char cup;
    int weight;
};

我们直接用宏替换就好了,把private替换成public。并且这个其实也是做ut时候的常规做法……

代码语言:javascript
复制
// test_sensei.cpp
#include <iostream>
using namespace std;

#define private public
#include "sensei.h"
#undef private

int main() {
    Sensei sensei(160, 80, 'B');
    cout<<sensei.height<<endl;
    cout<<sensei.cup<<endl;
    cout<<sensei.weight<<endl;
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档