C++ 类和对象从基础语法到高级特性深度解析

 更新时间:2026年01月10日 11:43:41   作者:xie_pin_an  
本文深入探讨了C++类和对象的核心概念,包括类的定义、访问控制、实例化、this指针、默认成员函数(构造、析构、拷贝构造、赋值重载)、以及高级特性,感兴趣的朋友跟随小编一起看看吧

在 C++ 编程中,类和对象是面向对象编程(OOP)的核心基石,封装、继承、多态三大特性均围绕其展开。本文将从类的定义与实例化、默认成员函数、高级特性等维度,结合实战代码,系统梳理类和对象的关键知识点,帮助开发者夯实 OOP 基础。

一、类的基础认知:定义、访问控制与实例化

1.1 类的定义格式

C++ 使用class关键字定义类(struct也可定义类,兼容 C 语言用法且支持成员函数),类体包含成员变量(属性)和成员函数(方法),结束时必须加分号。为区分成员变量与局部变量,惯例是给成员变量加前缀(如_)或后缀,例如_yearm_month

class Date {
public:
    // 成员函数:初始化日期
    void Init(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    // 成员变量:加前缀_区分
    int _year;
    int _month;
    int _day;
}; // 分号不可省略

1.2 访问限定符:封装的核心实现

访问限定符控制成员的访问权限,是封装特性的直接体现:

  • public:类外可直接访问(通常暴露接口函数);
  • private/protected:类外不可直接访问(通常隐藏成员变量,继承时二者有差异);
  • 访问权限作用域:从限定符出现位置到下一个限定符结束,class默认privatestruct默认public

1.3 类域与成员函数分离

类定义了独立的作用域,类外实现成员函数时需用::作用域操作符指明所属类,否则编译器会视为全局函数。

// 类内声明,类外实现
void Date::Init(int year, int month, int day) {
    _year = year;
    _month = month;
    _day = day;
}

1.4 类的实例化

类是对象的 “设计图”,仅声明成员变量(未分配空间),实例化是通过类创建对象并分配物理内存的过程。一个类可实例化多个对象,每个对象拥有独立的成员变量存储空间,成员函数则共享(存储在代码段)。

int main() {
    Date d1; // 实例化对象d1,分配内存
    d1.Init(2024, 10, 1); // 调用成员函数初始化
    return 0;
}

1.5 对象大小计算

对象仅存储成员变量,大小遵循内存对齐规则(与结构体一致),目的是提高访问效率:

  1. 第一个成员偏移量为 0;
  2. 其他成员对齐到 “对齐数”(编译器默认值与成员大小的较小值,VS 默认 8)的整数倍;
  3. 总大小为最大对齐数的整数倍;
  4. 无成员变量的类对象大小为 1 字节(占位标识对象存在)。
class A {
private:
    char _ch; // 1字节
    int _i;   // 4字节,对齐数4
};
// 内存对齐后大小:8字节(1+3填充+4)
cout << sizeof(A) << endl; // 输出8

二、this 指针:对象的 “隐藏身份标识”

2.1 核心问题

多个对象共享成员函数,函数如何区分操作的是哪个对象?例如d1.Init()d2.Init(),函数需知道当前操作的是d1还是d2

2.2 本质与特性

C++ 编译器在成员函数形参第一个位置隐含添加this指针(类型为类名* const),指向当前调用函数的对象,函数体内访问成员变量本质是通过this指针访问(可显式使用,不可显式声明)。

// 编译器优化后的Init函数原型
void Date::Init(Date* const this, int year, int month, int day) {
    this->_year = year; // 显式使用this
    _month = month;    // 隐式使用this
}
// 调用时编译器自动传递对象地址
d1.Init(2024, 10, 1); // 等价于d1.Init(&d1, 2024, 10, 1)

2.3 经典面试题解析

// 题目1:编译运行结果?
class A {
public:
    void Print() { cout << "A::Print()" << endl; }
private:
    int _a;
};
int main() {
    A* p = nullptr;
    p->Print(); // 正常运行:Print未访问成员变量,无需解引用p
    return 0;
}
// 题目2:编译运行结果?
class A {
public:
    void Print() { cout << _a << endl; } // 访问成员变量,需解引用this
private:
    int _a;
};
int main() {
    A* p = nullptr;
    p->Print(); // 运行崩溃:this为nullptr,解引用出错
    return 0;
}

三、默认成员函数:编译器的 “自动实现”

当用户未显式定义时,编译器会自动生成 6 个默认成员函数,核心是前 4 个:构造、析构、拷贝构造、赋值重载。

3.1 构造函数:对象的 “初始化器”

  • 功能:替代Init函数,对象实例化时自动调用,初始化成员变量;
  • 特性
    1. 函数名与类名相同,无返回值(无需写void);
    2. 可重载(无参、带参、全缺省);
    3. 无显式定义时,编译器生成默认构造(对内置类型不初始化,自定义类型调用其默认构造);
    4. 无参、全缺省、编译器默认生成的构造,统称 “默认构造”(不传参即可调用)。
class Date {
public:
    // 全缺省构造(推荐,兼顾多种初始化场景)
    Date(int year = 1, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
// 实例化方式
Date d1; // 调用全缺省构造,默认1-1-1
Date d2(2024, 10, 1); // 调用带参构造

3.2 析构函数:对象的 “清理工”

  • 功能:替代Destroy函数,对象生命周期结束时自动调用,释放资源(如堆内存);
  • 特性
    1. 函数名~类名,无参数无返回值;
    2. 一个类仅一个析构函数(不可重载);
    3. 无显式定义时,编译器生成默认析构(对内置类型不处理,自定义类型调用其析构);
    4. 有资源申请(如mallocnew)时必须显式定义,否则内存泄漏。
class Stack {
public:
    Stack(int n = 4) {
        _a = (int*)malloc(sizeof(int) * n);
        _capacity = n;
        _top = 0;
    }
    // 显式定义析构,释放堆内存
    ~Stack() {
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }
private:
    int* _a;
    size_t _capacity;
    size_t _top;
};

3.3 拷贝构造函数:对象的 “复制器”

  • 功能:用已有对象初始化新对象(如Date d2 = d1);
  • 特性
    1. 第一个参数必须是const 类名&(传值会引发无穷递归),后续参数可带默认值;
    2. 无显式定义时,编译器生成默认拷贝构造(内置类型值拷贝 / 浅拷贝,自定义类型调用其拷贝构造);
    3. 浅拷贝问题:若成员变量指向堆内存(如Stack_a),会导致多个对象共享同一块内存,析构时重复释放崩溃,需显式实现深拷贝。
Stack::Stack(const Stack& st) {
    // 深拷贝:为新对象分配独立内存
    _a = (int*)malloc(sizeof(int) * st._capacity);
    if (_a == nullptr) perror("malloc fail");
    memcpy(_a, st._a, sizeof(int) * st._top);
    _top = st._top;
    _capacity = st._capacity;
}

3.4 赋值运算符重载:对象的 “赋值器”

  • 功能:两个已存在对象间的赋值(如d1 = d2),区别于拷贝构造(初始化新对象);
  • 特性
    1. 必须重载为成员函数,函数原型类名& operator=(const 类名&)
    2. 返回类名&支持连续赋值(如d1 = d2 = d3);
    3. 需检查自赋值(if (this != &d)),避免重复释放;
    4. 无显式定义时,编译器生成默认赋值重载(浅拷贝,需资源的类需显式实现深拷贝)。
Date& Date::operator=(const Date& d) {
    if (this != &d) { // 避免自赋值
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    return *this; // 支持连续赋值
}

四、高级特性:提升代码灵活性与效率

4.1 初始化列表:成员变量的 “初始化源头”

  • 格式:构造函数后加:,后跟成员变量初始化表达式(成员变量(值), ...);
  • 必要性:引用成员、const成员、无默认构造的自定义类型成员,必须通过初始化列表初始化;
  • 注意:初始化顺序与类中成员声明顺序一致,与列表顺序无关。
class Date {
public:
    // 初始化列表初始化
    Date(int year, int month, int day, int& ref)
        : _year(year)
        , _month(month)
        , _day(day)
        , _ref(ref) // 引用必须初始化
        , _n(10)    // const成员必须初始化
    {}
private:
    int _year;
    int _month;
    int _day;
    int& _ref;    // 引用成员
    const int _n; // const成员
};

4.2 static 成员:类的 “共享资源”

  • 静态成员变量
    1. static修饰,所有对象共享,存储在静态区;
    2. 类内声明,类外初始化(类型 类名::变量名 = 值);
    3. 受访问限定符控制,可通过类名::变量对象.变量访问。
  • 静态成员函数
    1. static修饰,无this指针;
    2. 仅可访问静态成员变量 / 函数,不可访问非静态成员。

应用场景:统计对象创建个数:

class A {
public:
    A() { ++_scount; }
    A(const A&) { ++_scount; }
    ~A() { --_scount; }
    static int GetCount() { return _scount; } // 静态成员函数
private:
    static int _scount; // 静态成员变量
};
int A::_scount = 0; // 类外初始化
int main() {
    A a1, a2;
    cout << A::GetCount() << endl; // 输出2
    return 0;
}

4.3 友元:突破封装的 “特殊权限”

友元允许外部函数 / 类访问类的私有成员,分为友元函数和友元类,慎用(破坏封装)

  • 友元函数:非成员函数,类内声明时加friend
  • 友元类:类 A 是类 B 的友元,则 A 的所有成员函数可访问 B 的私有成员(单向关系,不可传递)。
class Date {
    // 友元声明:operator<<可访问私有成员
    friend ostream& operator<<(ostream& out, const Date& d);
private:
    int _year;
    int _month;
    int _day;
};
// 全局函数实现
ostream& operator<<(ostream& out, const Date& d) {
    out << d._year << "-" << d._month << "-" << d._day;
    return out;
}
// 使用
Date d(2024, 10, 1);
cout << d << endl; // 输出2024-10-1

4.4 匿名对象:临时使用的 “无名称对象”

  • 格式类名(实参),生命周期仅当前行;
  • 场景:临时调用成员函数,无需定义命名对象。
class Solution {
public:
    int Sum(int n) { return n*(n+1)/2; }
};
// 匿名对象调用函数
int ret = Solution().Sum(100); // 输出5050

五、C++ vs C 语言:封装的优势

Stack为例,对比 C 语言与 C++ 的实现差异:

特性C 语言实现C++ 实现
数据与函数关系分离(函数需显式传结构体指针)封装(数据 + 函数在类内,this 指针隐式传递)
访问控制无,可直接修改结构体成员访问限定符控制,私有成员不可直接修改
初始化与清理需手动调用Init/Destroy构造 / 析构函数自动调用,避免遗漏
代码简洁性需 typedef,函数参数繁琐类名直接作为类型,语法更简洁

六、总结

类和对象是 C++ 面向对象编程的核心,核心要点可概括为:

  1. 封装:通过类整合数据与函数,访问限定符控制权限;
  2. 默认成员函数:构造(初始化)、析构(清理)、拷贝构造(复制新对象)、赋值重载(对象赋值)是基础,需区分使用场景;
  3. 高级特性:初始化列表解决特殊成员初始化,static 成员实现共享资源,友元灵活访问私有成员(慎用),匿名对象简化临时操作;
  4. 内存与效率:理解 this 指针、内存对齐、编译器拷贝优化,避免内存泄漏和性能问题。

到此这篇关于C++ 类和对象全解析:从基础语法到高级特性的文章就介绍到这了,更多相关C++ 类和对象内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言的常量,字符串,转义字符,注释你都了解吗

    C语言的常量,字符串,转义字符,注释你都了解吗

    这篇文章主要为大家详细介绍了C语言的常量,字符串,转义字符,注释,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • Objective-C 消息传递机制详解

    Objective-C 消息传递机制详解

    Objective-C语言中方法的传递有二种:①Selector ② Blocks,本文主要说一下Selector,本文以Objective-C 消息传递机制进行详细介绍,关于Blocks会在后续总结一下
    2012-11-11
  • Qt快速读取大文件最后一行内容解决方案

    Qt快速读取大文件最后一行内容解决方案

    这篇文章主要给大家介绍了关于Qt如何快速读取大文件最后一行内容的解决方案,文中通过代码介绍的非常详细,对大家学习或者使用Qt具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-01-01
  • c++优先队列(priority_queue)用法详解

    c++优先队列(priority_queue)用法详解

    这篇文章主要介绍了c++优先队列(priority_queue)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • C++实现简单贪吃蛇小游戏

    C++实现简单贪吃蛇小游戏

    这篇文章主要为大家详细介绍了C++实现简单贪吃蛇小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • 下标操作符重载模拟多维数组详解

    下标操作符重载模拟多维数组详解

    虽然不能直接实现一对下标操作符重载,但是我们可以间接模拟。思路是这样的,先通过单下标操作返回一个具有下标操作能力的左值,对左值进行下标操作,两个下标操作表达式联立就实现了双下标操作
    2013-09-09
  • C语言编程简单却重要的数据结构顺序表全面讲解

    C语言编程简单却重要的数据结构顺序表全面讲解

    这篇文章主要为大家介绍了C语言编程中非常简单却又非常重要的数据结构顺序表的全面讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-10-10
  • c++中for双循环的那些事

    c++中for双循环的那些事

    本人很菜,今天看《C++编程思想》中的一道课后题中说到这样一个问题。修改两层嵌套的for循环的标识符,观察结果变化
    2013-05-05
  • C语言求字符串长度的四种方法实例代码

    C语言求字符串长度的四种方法实例代码

    在C语言的应用过程中经常性的会用到字符串,以及对字符串的长度进行计算的问题,下面这篇文章主要给大家介绍了关于C语言求字符串长度的四种方法的相关资料,需要的朋友可以参考下
    2022-12-12
  • VSCode配置C++环境的方法步骤(MSVC)

    VSCode配置C++环境的方法步骤(MSVC)

    这篇文章主要介绍了VSCode配置C++环境的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05

最新评论