类与对象(上)
类名 对象名(参数1, 参数2...);class Datepublic://Init: 成员函数,用于给成员变量赋值_day = day;private://成员变量,这里仅仅是声明,不占实际内存空间int _year;int _month;int _day;int main()// --- 类的实例化 ---// 这一步在栈区为 d1 分配了空间(大小通常为 12 字节)// 此时d1已经存在
一.类的基本概念
1.语法形式:
//类头 (Class-head)
class 类名
{
//成员规范 (Member-specification)
public:
// 公有成员(外部接口)
[数据成员声明];
[成员函数声明/定义];
protected:
//受保护成员(用于继承)
[数据成员声明];
private:
//私有成员(内部封装)
[数据成员声明];
}; // <--- 必须有分号,这在标准中被称为声明语句的结束
2.详细解释:
<1>.class为类的关键字,类名相当于类的名字,{}中为类的主体,最后}的;是不可以少的,类中的内容为类的内容,类中的变量称为成员变量,类中的函数成为成员函数。
<2>.public,private,protected均为访问限定符,其中public修饰的成员在类外可以直接访问,而private,protected修饰的成员在类外不可以直接访问,但在类里面可以访问,并且private与protected是有区别的,所以后续我会经常用private。
<3>.C++兼容C语言,所以在C++中struct也被升级为了类,但struct中的成员默认被public修饰,
如果class无访问限定符,则class中的成员默认被private修,但一般情况下推荐使用class定义类。
<4>.定义在类里面的成员函数默认inline。
3.类域与点操作符
<1>.类域:即定义一个新的作用域,类的所用成员都在类的作用域中,所以在类外使用成员时,要用::作用域操作符指明成员属于呢那一个类域。
例如:
class Date
{
public:
//成员函数
void Init();
void Print();
private:
int _year;
};
void Date::Init()
{
//有了 Date::指明领地,这里可以直接访问私有变量 _year
_year = 10;
}
//指明Print 函数属于 Date 这个类域
void Date::Print()
{
cout << _year << endl;
}
<2>.点操作符
我们应该明白的是在类域外面,绝对不可以直接使用成员函数与成员变量,但在类域内部,可以直接使用,那么此时我们应该使用.操作符,但这也牵扯到对象的实例化,所以接下来就是它啦。
二.实例化概念
1.概念:
<1>.用类类型在内存中创建对象的过程,称为类实例化出对象。
<2>.类是对象进行一种抽象描述,限定了类有哪些成员变量,这些成员变量只是声明,没有分配空间,用类实例化出对象时,才会分配空间。
<3>.一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。打个比方:类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,设计图规划了有多少个房间,房间大小功能等,但是并没有实体的建筑存在,也不能住人,用设计图修建出房子,房子才能住人。同样类就像设计图一样,不能存储数据,实例化出的对象分配物理内存存储数据。
2.定义方式
语法: 类名 对象名(参数1, 参数2...);
例如:
Date d1(2026,1,30);
详细的例子与解释:
#include<iostream>
using namespace std;
class Date
{
public:
//Init: 成员函数,用于给成员变量赋值
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;
};
int main()
{
// --- 类的实例化 ---
// 这一步在栈区为 d1 分配了空间(大小通常为 12 字节)
// 此时d1已经存在,但内部的 _year 等是随机值
Date d1;
// --- 使用对象调用成员函数 ---
// 通过 "." 操作符,让对象 d1 执行它的 Init 功能
d1.Init(2026, 2, 28);
// 让对象 d1 执行它的 Print 功能
d1.Print();
return 0;
}
建议:为了区分成员变量和用于给成员变量赋值的参数,我们可以给成员变量加一个特殊标识符,
3.对象的大小
<1>. 成员变量:就是对象占据的空间:当我们Date d1; 时,是为成员变量分配了空间(因为变量就是对象的“身体”),但没有为成员函数分配空间(因为函数是“公共设施”)。当你写 Date d1; 时,编译器在栈上开辟了一块内存。这块内存的大小,正好就是所有成员变量大小的总和。
<2>.成员函数:存储在公共代码区,对象内部并不包含成员函数的代码,实例化对象时,不会为函数分配新空间。
特点:
唯一性:无论你定义了 1 个 d1 还是 100 个 d2, d3...,成员函数(如 Init, Print)的代码在内存中永远只有一份,存放在专门的代码段中。
共享性:所有的对象共用这一份代码。当你调用 d1.Print() 时,CPU 只是跳转到那个公共地址去执行指令。
三.this指针
1.既然我们已经知道成员函数在内存中只有一份公用的代码,那么问题就来了:
Date d1;
d1.Print();
Date d2;
d2.Print();
当 d1.Print() 和 d2.Print() 调用的是同一段代码时,这段代码是如何精准地知道该打印 d1 的 2026 年,而不是 d2 的 2025 年呢?
这就是this 指针存在的作用:区分调用对象。
当我们定义 Print 函数时,我们以为它是这样的:
void Print() { ... }
但是编译器实际把它变成了这样(伪代码):
// 编译器偷偷加了一个隐含的参数:this 指针
void Print(Date* const this) {
// 所有的成员变量访问,其实都变成了通过 this 访问
cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
}
当调用 d1.Print() 时,编译器也偷偷动了手脚:
// 编译器自动把 d1 的地址传了进去
Date::Print(&d1);
2.特点
<1>.隐含性:你不需要在参数列表里写它,编译器自动加、自动传,并且C++规定不能在实参与形参的位置显示的写this指针,但是可以在函数体内显示的使用this指针
例如:
// 编译器会报错:你不能在括号里跟它抢着定义 this
void Date::Print(Date* this) // ❌ 语法错误:不能显式写形参
{
cout << _year << endl;
}
int main() {
Date d1;
d1.Print(&d1); // ❌ 语法错误:不能显式传实参
}
<2>.只读性:它的类型是 Date* const this,意味着你不能在函数内部让 this 指向别的对象(你不能写 this = &d2;)。
<3>.生命周期:它只存在于成员函数的执行期间。函数开始运行,它被压入栈;函数结束,它就消失。
更多推荐

所有评论(0)