承接上文:上一节我们学习了class基础语法与public/private访问权限,理解面向对象封装思想。本节拆解类内部两大核心组成:成员变量、成员函数,讲解二者的内存特性,同时落地C++类开发的工程编码规范,养成干净、易维护的代码写法,规避新同学常见编码陋习。
学习说明
类本质就是把**数据(成员变量)和操作数据的行为(成员函数)**打包在一起。成员变量描述对象有什么属性;成员函数描述对象能做什么行为。 很多新手写类时随意命名、权限乱设,埋下大量隐性bug。本节除语法外,重点落地工程编码规范,为后续构造函数、继承章节打好基础。
本节学习目标
- 分清成员变量、成员函数的概念,理解成员函数的隐式this指针基础认知
- 掌握成员访问规则:类内任意访问,类外只能访问public成员
- 掌握类成员基础内存特性:成员函数不属于单个对象,多个对象共享同一份成员函数代码
- 建立C++类工程编码规范,区分好习惯与不良写法
一、成员变量(属性)
成员变量用来保存对象自身的数据,每个实例对象拥有独立一份成员变量。
- 一般放在
private,禁止外部直接修改,保证封装性 - 命名规范:推荐加前缀
m_,例如m_name、m_age,一眼区分局部变量和成员变量
#include <iostream> #include <string> using namespace std; class Person { private: // 成员变量,私有,外部不可直接访问 string m_name; int m_age; public: // setter 设置成员变量 void setName(string name) { m_name = name; } void setAge(int age) { // 增加数据校验 if(age > 0 && age < 150) { m_age = age; } else { cout << "年龄输入非法" << endl; } } // getter 获取成员变量 string getName() { return m_name; } int getAge() { return m_age; } }; int main() { Person p1; p1.setName("张三"); p1.setAge(20); cout << p1.getName() << "," << p1.getAge() << "岁" << endl; return 0; }二、成员函数(行为)
成员函数是类内部定义的函数,用来操作本类的成员变量。
- 成员函数代码存放在代码段,所有对象共用一份成员函数,不会每个对象都复制函数指令
- 成员函数内部自带隐式
this指针,指向调用这个函数的对象实例 - 成员函数可以访问本类所有成员,不管是public还是private
this指针简单理解:p1调用setAge时,this指向p1;p2调用setAge时,this指向p2。 完整this示例:
class Person { private: int m_age; public: void setAge(int age) { this->m_age = age; // this->可以省略,编译器自动补全 // 等价于 m_age = age; } };三、核心内存特性重点
- 每个对象独立分配成员变量内存,对象之间互不干扰
- 成员函数不占用对象内存,多个对象共享函数代码
- this指针是成员函数形参,编译阶段自动添加,用来区分是哪个对象在调用函数
验证小实验:sizeof(Person)只会统计成员变量占用大小,成员函数不计入。
四、C++类基础工程编码规范
✅ 推荐规范
- 成员变量默认放private,对外提供getter/setter读写,增加数据校验
- 成员变量命名:
m_xxx前缀,区分局部变量、全局变量 - 类名采用大驼峰:
Person、Student - 成员函数小驼峰:
setName、getAge - 类定义末尾加分号,新手高频漏写
- 类的声明和实现分离(简单示例可写一起,工程项目建议头文件声明、cpp实现)
头文件与源文件分离极简示例
// Person.h #pragma once #include <string> using namespace std; class Person { private: string m_name; public: void setName(string name); string getName(); };// Person.cpp #include "Person.h" void Person::setName(string name) { m_name = name; } string Person::getName() { return m_name; }不推荐陋习
- 把所有成员全部写public,直接外部修改成员变量,破坏封装
- 成员变量和局部变量同名,不做区分,可读性差
- 类定义末尾忘记分号,引发诡异编译报错
- 成员函数内不做参数校验,任由非法数据写入成员变量
五、高频坑点总结
- 误区:每个对象都会单独保存成员函数。 函数代码共享,只有成员变量每个对象独立。
- 类外只能访问public成员;private成员只能在类内部访问。
- this指针仅存在于非静态成员函数中,静态成员函数没有this指针(后续章节讲解静态)。
- 对象创建后成员变量不会自动初始化,直接使用会得到随机值。解决方法:使用构造函数初始化(下一节讲解)。
六、本节思考题
- 一个类有2个对象p1、p2,修改p1的m_age,会不会影响p2的m_age?为什么?
- sizeof统计类大小的时候,成员函数会不会占用空间?
- 为什么工程代码里成员变量优先放到private,而不是public?
class Test { private: int m_val; public: void setVal(int val) { m_val = val; } }; int main() { Test t; t.setVal(10); return 0; }问:t调用setVal时,this指针指向谁?m_val = val底层等价于什么写法?
下期预告
下一节:构造函数与初始化列表:解决const、引用成员初始化坑点。