一.类的基本概念

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>.生命周期:它只存在于成员函数的执行期间。函数开始运行,它被压入栈;函数结束,它就消失。

 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐