成员变量和成员函数分开存储
只有非静态成员属于对象
class person
{
};
void test01()
{
Person p;
cout << "size of p = " << sizeof(p) << endl;
};
1、空对象占用内存空间为:1
2、C++编译器会给每个空对象也分配一个字节空间,是为了区分空对象占内存的位置
3、每个空对象也应该有一个独一无二的内存地址
class Person
{
int m_A; 非静态成员变量 属于类的对象上
static int m_B; 静态成员变量 不属于类对象上
void func() {} 非静态成员函数 不属于类对象上
static void func2() {} 静态成员函数 不属于类的对象上
}
void test01()
{
Person p;
cout << "size of p = " << sizeof(p) << endl;
};
输出结果为4个字节,对应int m_A
至于为什么不是1+4=5个字节大小,这关于内存对齐,后续会学。
this指针概念
成员变量和成员函数是分开存储的,每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。
那么问题是:这一块代码是如何区分哪个对象调用自己的呢?
C++通过提供特殊的对象指针,this指针,解决上述问题。
this指针指向被调用的成员函数所属的对象。
this指针是隐含每一个非静态成员函数内的一种指针。
this指针不需要定义,直接使用即可。
this指针的用途
解决名称冲突
- 当形参和成员变量同名时,可用this指针来区分
class Person
{
public:
Person(int age)
{
this->age = age;(√) this指针指向被调用的成员函数所属的对象。
age = age;(×)
}
int age;
}; 这里this就指向有参构造函数Person()所属的对象p1
void test01()
{
Person p1(18);
cout << "p1的年龄为:" << p1.age << endl;
}
- 在类的非静态成员函数中返回对象本身,可使用return *this
class Person
{
public:
Person(int age)
{
this->age = age;(√)
age = age;(×)
}
Person& PersonAddAge(Person &p) 引用方式返回对象,不会复制创建新的对象,若用
{ 若用值的方式返回,则会创建一个p2',再调用又会创建p2''
this->age += p.age;
//this指向p2的指针,而*this指向的就是p2这个对象本体
return *this;
}
int age; this指针指向被调用的成员函数所属的对象。
}; 这里this就指向有参构造函数Person()所属的对象p1
void test02()
{
年龄相加
Person p1(10);
Person p2(10);
链式编程思想 若要像这样连续调用,则我们需要返回p2
p2.PersonaAddAge(p1).PersonaAddAge(p1).PersonaAddAge(p1);
若用值的方式返回,则会创建一个p2',再调用又会创建p2''
cout << "p2的年龄为:" << p2.age << endl;
}
空指针访问成员函数
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针。
如果用到this指针,需要加以判断保证代码的健壮性
if (this == null) {
return;
} 可通过这段代码防止空指针访问成员函数报错
如果成员函数中使用了
this
指针,而this
指针是空的,那么程序将表现出未定义行为。未定义行为可能导致程序崩溃、数据损坏或其他不可预测的结果。
this
指针用于访问对象的成员变量和调用其他成员函数。如果this
指针为空,任何试图通过它访问成员的操作都会导致访问违规(Access Violation),从而导致程序崩溃。、
const修饰成员函数
常函数
- 成员函数后加const后我们称为这个函数为常函数
- 常函数内不可以修改成员属性
- 成员属性声明时加关键字mutable后,在常函数中依然可以修改
class Person{
this指针的本质 是指针常量 指针的指向是不可以修改的
在成员函数后面加const,修饰的是this指向,让指针指向的值也不可以修改
则此时的形式为 const Person * const this;
void showPerson() const
{
this->m_B = 100;
//this->m_A = 100;
//this = NULL; //this指针不可以修改指针的指向的
}
int m_A;
mutable int m_B;
特殊变量,即使在常函数中,也可以修改这个值,加关键字mutable
}
void test01()
{
Person p;
p.showPerson();
}
常对象:
- 声明对象前加const称该对象为常对象
- 常对象只能调用常函数
常对象
void test02()
{
const Person p; 在对象前加const,变为常对象
//p.m_A = 100;
p.m_B = 100; m_B是特殊值,在常对象下也可以修改
}
p.func(); 常对象 不可以调用普通成员函数,因为普通成员函数可以修改属性
AI整理后的C++核心概念笔记 (成员变量、this指针、常函数)
一、成员变量与成员函数存储规则
类型 | 存储位置 | 是否属于对象 | 示例 |
---|---|---|---|
非静态成员变量 | 对象内存中 | ✔️ | int m_A; |
静态成员变量 | 全局数据区 | ❌ | static int m_B; |
非静态成员函数 | 代码区 | ❌ | void func() {} |
静态成员函数 | 代码区 | ❌ | static void func2() {} |
关键结论:
- 空对象默认占 1字节(确保对象有唯一地址)。
- 对象大小 = 非静态成员变量总大小(内存对齐后)。
class Person {}; // sizeof(Person) = 1
class Person { int m_A; }; // sizeof(Person) = 4
二、this指针核心机制
1. 本质与特性
- 隐含指针:每个非静态成员函数自动包含
Person* const this
(指针常量,指向不可变)。 - 用途:
- 解决名称冲突:区分成员变量与形参。
- 链式调用:返回对象本体(
return *this;
)。
2. 代码示例
// 解决名称冲突
Person(int age) {
this->age = age; // ✅ 明确指向成员变量
}
// 链式调用
Person& PersonAddAge(Person& p) {
this->age += p.age;
return *this; // 返回对象本体(而非副本)
}
// 使用
Person p2(10);
p2.PersonAddAge(p1).PersonAddAge(p1); // p2.age累加两次
3. 空指针访问成员函数
- 风险:空指针调用依赖
this
的函数会导致崩溃。 - 防护:增加空指针检查。
void printAge() {
if (this == nullptr) return; // ✅ 健壮性检查
cout << this->age;
}
三、const修饰成员函数(常函数)
1. 规则与特性
类型 | 语法 | this指针形式 | 能否修改成员变量 |
---|---|---|---|
普通函数 | void func() {...} | Person* const this | ✔️ |
常函数 | void func() const | const Person* const this | ❌(除非变量用mutable ) |
2. 代码示例
class Person {
public:
void show() const { // 常函数
// this->m_A = 100; ❌ 编译错误
this->m_B = 100; // ✅ mutable变量允许修改
}
int m_A;
mutable int m_B;
};
// 常对象
const Person p;
// p.m_A = 200; ❌ 常对象禁止修改普通成员
p.m_B = 200; // ✅ 允许修改mutable成员
3. 重要规则
- 常对象只能调用 常函数(普通函数可能修改成员,违反const语义)。
const Person p;
p.show(); // ✅ 常对象调用常函数
// p.func(); ❌ 禁止调用普通函数
四、核心概念总结
概念 | 核心要点 |
---|---|
空对象内存 | 占1字节,保证对象有唯一地址。 |
this指针 | 隐含指针,指向调用者对象;支持链式编程和解决命名冲突。 |
常函数 | 用const 修饰,禁止修改成员变量(mutable 例外)。 |
常对象 | 用const 修饰,只能调用常函数,禁止修改非mutable 成员。 |
关联记忆:
this->
明确指向 → 常函数锁成员 → 常对象限调用 → mutable破约束。