Skip to content

Commit

Permalink
Improve c-object-model
Browse files Browse the repository at this point in the history
  • Loading branch information
selfboot committed Mar 31, 2024
1 parent 53092be commit 4c692e8
Showing 1 changed file with 75 additions and 2 deletions.
77 changes: 75 additions & 2 deletions source/_drafts/c-object-model.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: 结合实例深入浅出理解 C++ 对象的内存布局
title: 结合实例深入理解 C++ 对象的内存布局
tags: [C++]
category: 程序设计
toc: true
Expand Down Expand Up @@ -142,9 +142,82 @@ $ g++ basic_method.cpp -o basic_method_O2 -O2 -g -std=c++11

## 特殊成员内存分布

上面的成员都是 public 的,如果是 private(私有) 变量,私有方法呢?另外,静态成员变量或者静态成员方法,在内存中又是怎么布局呢?
### 私有成员

先来看私有成员,接着上面的例子,增加私有成员变量和方法。整体代码如下:

```c++
#include <iostream>

class Basic {
public:
int a;
double b;

void setB(double value) {
b = value; // 直接访问成员变量b
secret(b);
}
private:
int c;
double d;

void secret(int temp) {
d = temp + c;
}
};

int main() {
Basic temp;
temp.a = 10;
temp.setB(3.14);
return 0;
}
```
编译之后,通过 GDB,可以打印出所有成员变量的地址,发现这里**私有变量的内存布局并没有什么特殊地方,也是依次顺序存储在对象**中。私有的方法也没有特殊地方,一样存储在文本段。整体布局如下如:
![]()
那么 **private 是在运行期还是编译期进行可见性控制的**呢?首先编译期肯定是有保护的,这个很容易验证,我们无法直接访问 temp.c ,或者调用 secret 方法,因为直接会编译出错。
那么运行期是否有保护呢?我们来验证下。前面已经验证 private 成员变量也是根据偏移来找到内存位置的,我们可以在代码中直接根据偏移找到内存位置并更改里面的值。
```c++
int* pC = reinterpret_cast<int*>(reinterpret_cast<char*>(&temp) + 16);
*pC = 12; // 直接修改c的值
```

这里修改后,可以增加一个show方法打印所有成员的值,发现这里temp.c 确实被改为了 12。私有方法和普通成员方法一样存储在文本段,我们拿到其地址后,可以通过这个地址调用吗?这里需要一些骚操作,我们**在类定义中添加额外的接口来暴露私有成员方法的地址**,然后通过成员函数指针来调用私有成员函数。整体代码如下:

```c++
class Basic {
...
public:
// 暴露私有成员方法的地址
static void (Basic::*getSecretPtr())(int) {
return &Basic::secret;
}

...
}

int main() {
// ...
void (Basic::*funcPtr)(int) = Basic::getSecretPtr();
// 调用私有成员函数
(temp.*funcPtr)(10);
// ...
}
```
上面代码正常运行,你可以通过 print 打印调用前后成员变量的值来验证。看来对于成员函数来说,只是编译期不让直接调用,运行期并没有保护,我们可以绕过编译限制在对象外部调用。
当然实际开发中,**千万不要直接通过地址偏移来访问私有成员变量**,也不要通过各种骚操作来访问私有成员方法,这样不仅破坏了类的封装性,而且是不安全的。
### 静态成员
### 私有成员
## 简单继承
Expand Down

0 comments on commit 4c692e8

Please sign in to comment.