导读:本期聚焦于小伙伴创作的《C++类的内部结构中成员变量和成员函数是如何存储的》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++类的内部结构中成员变量和成员函数是如何存储的》有用,将其分享出去将是对创作者最好的鼓励。

C++的类是对数据和操作的封装,很多开发者在使用类的时候会好奇,当我们创建一个类的多个对象时,成员变量和成员函数分别是怎么存储的,对象之间是否会重复存储成员函数的代码。要搞清楚这个问题,需要先了解C++类内部的存储设计逻辑。

C++类的内部结构中成员变量和成员函数是如何存储的

C++类的内存存储基本规则

C++中类的成员分为成员变量和成员函数两大类,这两类成员在内存中的存储位置是完全不同的。成员变量的存储和对象强绑定,而成员函数的存储和类强绑定,所有同类对象共享同一份成员函数代码。

成员变量的存储特性

普通成员变量属于对象的实例数据,每个对象创建的时候都会在栈或者堆上分配独立的内存空间来存储自己的成员变量值。不同的对象之间的成员变量是互相隔离的,修改一个对象的成员变量不会影响其他对象的同名成员变量。

我们可以通过下面的代码来验证这个特性:

#include <iostream>
using namespace std;

class Student {
public:
    // 普通成员变量
    int age;
    string name;
};

int main() {
    Student s1;
    Student s2;
    s1.age = 18;
    s2.age = 20;
    // 两个对象的age成员互不影响
    cout << "s1 age: " << s1.age << endl; // 输出18
    cout << "s2 age: " << s2.age << endl; // 输出20
    // 查看两个对象的内存地址,成员变量地址不同
    cout << "s1 address: " << &s1 << endl;
    cout << "s2 address: " << &s2 << endl;
    return 0;
}

成员函数的存储特性

成员函数不属于某个具体的对象,而是属于整个类。类的所有成员函数会被编译后存放在代码段中,所有同类对象调用成员函数的时候,都是执行同一份代码。编译器会在编译阶段把成员函数和普通函数一样处理,只是会给成员函数添加一个隐式的this指针参数,用来指向调用该函数的对象,这样成员函数就能访问到对应对象的成员变量。

我们可以用下面的代码验证成员函数的共享特性:

#include <iostream>
using namespace std;

class Student {
public:
    int age;
    // 普通成员函数
    void printAge() {
        cout << "age: " << this->age << endl;
    }
};

int main() {
    Student s1;
    Student s2;
    s1.age = 18;
    s2.age = 20;
    // 两个对象调用同一个成员函数,输出各自的年龄
    s1.printAge(); // 输出age: 18
    s2.printAge(); // 输出age: 20
    // 查看两个成员函数地址,是相同的
    cout << "s1.printAge address: " << (void*)&Student::printAge << endl;
    cout << "s2.printAge address: " << (void*)&Student::printAge << endl;
    return 0;
}

特殊成员的存储差异

静态成员的特殊存储

静态成员变量和静态成员函数的存储规则和普通成员不同。静态成员变量属于类,不属于任何对象,所有对象共享同一份静态成员变量,它在程序启动阶段就会分配内存,存放在全局数据区。静态成员函数同样属于类,没有隐式的this指针,所以静态成员函数不能直接访问普通成员变量,只能访问静态成员。

下面的代码展示了静态成员的特性:

#include <iostream>
using namespace std;

class Student {
public:
    int age; // 普通成员变量
    static int totalCount; // 静态成员变量,记录学生总数
    // 静态成员函数
    static void addCount() {
        totalCount++;
    }
};

// 静态成员变量需要在类外初始化
int Student::totalCount = 0;

int main() {
    Student s1;
    Student s2;
    s1.age = 18;
    s2.age = 20;
    // 调用静态成员函数修改静态成员变量
    Student::addCount();
    Student::addCount();
    // 所有对象共享静态成员变量的值
    cout << "s1 totalCount: " << s1.totalCount << endl; // 输出2
    cout << "s2 totalCount: " << s2.totalCount << endl; // 输出2
    cout << "Student totalCount: " << Student::totalCount << endl; // 输出2
    return 0;
}

虚函数的存储特性

如果类中包含虚函数,那么类的存储结构会多一个虚函数表指针vptr,这个指针属于对象的实例数据,每个包含虚函数的对象都会有一个vptr,指向该类对应的虚函数表。虚函数表属于类,存放在常量区,所有同类对象共享同一份虚函数表。虚函数的调用会通过vptr找到虚函数表,再从表中找到对应的函数地址进行调用,这是C++实现多态的基础。

类对象内存大小的计算规则

类对象的大小只和成员变量有关,和成员函数无关。计算规则如下:

  • 普通成员变量的大小之和,需要考虑内存对齐规则
  • 如果存在虚函数,需要加上一个指针的大小,也就是vptr的大小,通常是8字节(64位系统)或者4字节(32位系统)
  • 静态成员变量不计入对象大小,因为静态成员属于类,不属于对象
  • 成员函数不计入对象大小,因为成员函数存放在代码段

下面的表格展示了不同类结构的对象大小(以64位系统为例):

类结构成员变量成员函数对象大小
空类1字节(编译器强制分配的最小大小)
只有普通成员变量的类int age, char gender8字节(int4字节+char1字节,对齐到8字节)
有普通成员和成员函数的类int agevoid print()4字节(仅计算int的大小)
有虚函数的类int agevirtual void print()12字节(int4字节 + vptr8字节,对齐到12字节)
有静态成员的类int age, static int count4字节(静态成员不计入)

我们可以通过代码验证对象大小的计算:

#include <iostream>
using namespace std;

class EmptyClass {};

class NormalClass {
public:
    int age;
    char gender;
};

class FuncClass {
public:
    int age;
    void print() {
        cout << age << endl;
    }
};

class VirtualClass {
public:
    int age;
    virtual void print() {
        cout << age << endl;
    }
};

class StaticClass {
public:
    int age;
    static int count;
};

int StaticClass::count = 0;

int main() {
    cout << "EmptyClass size: " << sizeof(EmptyClass) << endl; // 输出1
    cout << "NormalClass size: " << sizeof(NormalClass) << endl; // 输出8
    cout << "FuncClass size: " << sizeof(FuncClass) << endl; // 输出4
    cout << "VirtualClass size: " << sizeof(VirtualClass) << endl; // 输出16(64位系统vptr8字节,int4字节,对齐到16)
    cout << "StaticClass size: " << sizeof(StaticClass) << endl; // 输出4
    return 0;
}

常见问题说明

为什么成员函数可以通过this指针访问成员变量?

因为编译器在编译成员函数的时候,会隐式添加一个this指针参数,这个指针指向调用该成员函数的对象。当我们调用s1.printAge()的时候,编译器会把代码处理成printAge(&s1),这样成员函数内部就可以通过this指针访问到s1的成员变量。

为什么静态成员函数不能访问普通成员变量?

因为静态成员函数没有隐式的this指针,它不属于任何对象,所以无法知道要访问哪个对象的成员变量,只能访问属于类的静态成员。

理解C++类的内部存储结构,能够帮助开发者更好地掌握类的使用逻辑,在排查内存相关的问题时也能更快速定位原因,比如对象大小异常、成员访问错误等问题,都可以通过类存储规则来分析。

C++成员变量成员函数类内部结构修改时间:2026-07-01 03:48:49

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。