资讯动态

C++: 类与对象(上)

发布时间:2026/10/31 6:48:10 来源:尧图企业网站定制
1. 类的定义1.1 类定义格式在 C 中类是一种用户自定义的数据类型它将数据成员和成员函数封装在一起。类定义的基本格式如下class ClassName { // 成员变量 // 成员函数 }; // 注意末尾的分号定义在类里面的函数默认都为内联inline函数。例如定义一个简单的日期类class Date { public: void Init(int year, int month, int day) { _year year; _month month; _day day; } void Print() { cout _year - _month - _day endl; } private: int _year; int _month; int _day; };1.2 访问限定符C 提供了三种访问限定符用于控制类成员的访问权限public公有成员在类外可以直接访问。protected保护成员在类外不能直接访问但可以在派生类中访问。private私有成员在类外不能直接访问只能在类内部访问。访问限定符的作用域从该限定符出现的位置开始到下一个访问限定符出现之前结束。如果类class定义开头没有写访问限定符则默认是 private。1.3 类域类定义了一个新的作用域称为类域。类中的所有成员都位于类域中。在类外定义成员函数时需要使用作用域操作符::来指明成员所属的类。// 在类外定义成员函数 void Date::Print() { cout _year - _month - _day endl; }2. struct 来表示类在 C 中struct也可以当作类定义的关键字来使用。用struct定义的类与用class定义的类在功能上几乎完全一致都可以包含数据成员和成员函数也都可以使用访问限定符。两者的唯一区别在于默认的访问限定符不同struct的默认访问限定符是public即成员在类外可以直接访问。class的默认访问限定符是private即成员在类外不能直接访问。例如下面用struct定义一个日期类struct Date { // 默认是 public可以直接访问 void Init(int year, int month, int day) { _year year; _month month; _day day; } int _year; int _month; int _day; };因此在 C 中struct和class都可以用来定义类选择哪一个主要取决于默认访问权限的偏好希望成员默认公开时用struct希望成员默认私有时用class。注意struct 在 C 中可以直接作为类型来定义变量当然C中的做法同样兼容。typedef struct ListNode { int val; ListNode* next;//struct ListNode* next; };2. 实例化2.1 实例化概念用类类型创建对象的过程称为类的实例化。类本身只是一个模板不占用实际的存储空间只有实例化出对象后系统才会为对象分配内存。在类中的成员变量只是声明并未开空间。Date d1; // 实例化一个 Date 对象 Date d2; // 实例化另一个 Date 对象同一个类可以实例化出多个对象每个对象都拥有自己独立的数据成员存储空间但成员函数是共享的。2.2 对象大小对象的大小等于其所有非静态数据成员的大小之和同时需要考虑内存对齐规则。成员函数不占用对象空间因为它们存放在代码段中由所有对象共享。补充内存对齐的优势提高 CPU 访问内存的效率避免一次变量跨两次内存块读取适配部分硬件非对齐访问会直接报错崩溃有利于 CPU 缓存提升缓存命中率便于 DMA、硬件寄存器等底层硬件操作。内存对齐不是没有代价会产生内存空洞padding 填充字节浪费少量内存空间属于空间换时间。class A { public: void Func() {} // 成员函数不占对象空间 private: int _a; // 4 字节 char _b; // 1 字节考虑对齐后可能占 4 字节 }; // sizeof(A) 在 32 位平台下通常为 8 字节空类的大小为 1 字节这是为了区分不同的空对象地址。2.3 内存对齐规则内存对齐是指编译器在分配结构体或类对象的内存时按照一定的规则在成员之间插入填充字节padding使每个成员的起始地址满足对齐要求。C 中主要遵循以下几条规则第一个成员变量放在结构体 / 类偏移为0的地址处。其余成员变量存放起始地址必须是对齐数的整数倍。✅对齐数计算公式对齐数 min(编译器默认对齐数该成员自身大小)VS 默认对齐数8结构体 / 类整体总大小必须是最大对齐数的整数倍。最大对齐数所有成员各自对齐数里面的最大值。嵌套结构体场景被嵌套的结构体对齐到它自己的最大对齐数的整数倍地址。外层结构体总大小必须包含所有成员嵌套结构体也算整体是全部最大对齐数的整数倍。下面通过一个例子来理解对齐过程struct S { char _c; // 1 字节偏移 0 int _i; // 4 字节需对齐到 4 的倍数偏移 4 char _d; // 1 字节偏移 8 }; // 总大小 12 字节最大对齐数 412 是 4 的倍数 struct A { char a; // 1字节 int b; // 4字节 }; struct B { char x; // 1字节 struct A sa; //按照A最大对齐数4大小为8 double y; // 8字节 }; //总大小是243. this 指针C 编译器给每个非静态成员函数增加了一个隐藏的指针参数称为 this 指针。this 指针指向调用该成员函数的对象通过它可以在成员函数内部访问对象的成员。void Date::Print() { // this 指向调用 Print 的对象 cout this-_year - this-_month - this-_day endl; }this 指针的特点this 指针的类型是Class Name* const即指针本身不能被修改。this 指针是成员函数的隐含参数不需要也不能在调用时显式传递。this 指针存储在栈上是成员函数的一个局部变量。C规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理)但是可以在函数体内显示使用this指针。this 指针存在于内存中的栈。4. C 和 C 语言实现 Stack 对比下面分别用 C 语言和 C 实现一个栈对比两种语言在数据封装和代码组织上的差异。C 语言实现typedef struct Stack { int* _a; int _top; int _capacity; } Stack; void StackInit(Stack* ps) { ps-_a (int*)malloc(sizeof(int) * 4); ps-_top 0; ps-_capacity 4; } void StackPush(Stack* ps, int x) { if (ps-_top ps-_capacity) { ps-_capacity * 2; ps-_a (int*)realloc(ps-_a, sizeof(int) * ps-_capacity); } ps-_a[ps-_top] x; }C 语言中数据和操作数据的函数是分离的函数必须显式接收结构体指针作为参数并且结构体成员默认是公开的缺乏访问控制。C 实现class Stack { public: void Init() { _a new int[4]; //new 是C开辟空间的一个关键字后续介绍 _top 0; _capacity 4; } void Push(int x) { if (_top _capacity) { _capacity * 2; int* tmp new int[_capacity]; for (int i 0; i _top; i) tmp[i] _a[i]; delete[] _a; _a tmp; } _a[_top] x; } private: int* _a; int _top; int _capacity; };C 将数据和操作封装在类中成员函数通过 this 指针隐式访问对象数据代码更简洁同时通过 private 访问限定符保护数据增强了安全性。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑