
简介
该用户还未填写简介
擅长的技术栈
可提供的服务
暂无可提供的服务
上一篇我们定义了类,但每个对象创建后还要手动调用setXxx()来初始化,对象销毁前也没机会做清理。构造函数和析构函数解决了这两个问题——它们是被自动调用的特殊函数。构造函数在对象诞生时执行,适合做初始化(分配内存、设置初值);析构函数在对象消亡前执行,适合做清理(释放资源、关闭文件)。理解它们的调用时机和规则,是写出健壮C++代码的基础。
现实世界中的对象往往由更小的部件组成:汽车有发动机,电脑有CPU,人有一双手。在C++中,这种“整体-部分”(has-a)的关系通过类的组合来实现——把一个类的对象作为另一个类的成员变量。本篇讲清楚如何正确初始化这些成员对象、构造和析构的顺序是什么,以及为什么初始化列表是组合类的好朋友。
每个对象都有自己的成员变量,比如每个学生有自己的姓名和学号。但有些东西应该是全类共享的,比如学生总数、配置参数、全局计数器。static成员变量就是为此设计的——它不属于任何具体对象,而是属于类本身。static成员函数也一样,可以不通过对象直接调用。本篇讲清楚静态成员的存储方式、初始化规则、访问方法,最后用一个简单的单例模式展示它的实际用途。
如果派生类定义了一个和基类同名的成员(变量或函数),基类的那个成员会被“隐藏”——这不是重载,不是重写,而是作用域的覆盖。这是C++继承中一个容易混淆的规则。本篇讲清楚同名隐藏的发生条件、与函数重载/重写的区别,以及如何通过作用域运算符::强行访问被隐藏的基类成员
继承是面向对象实现代码复用的核心机制,也是建立“is-a”(是一种)关系的基础。C++提供了三种继承方式:公有继承(public)、保护继承(protected)、私有继承(private)。它们控制基类成员在派生类中的可见性——哪些成员能被派生类访问,哪些成员能被外界通过派生类访问。本篇用一张表讲清楚三者的区别,并重点解释为什么公有继承才是真正的“is-a”关系。
前几篇我们讲了虚函数和多态。但有一个至关重要的细节:如果基类的析构函数不是虚函数,删除基类指针时只会调用基类的析构函数,派生类的析构函数不会被调用——这意味着派生类中分配的资源永远不会被释放。这是C++中最隐蔽、最常见的内存泄漏来源之一。本篇讲清楚虚析构函数的必要性、实现原理,以及为什么几乎所有带虚函数的类都应该有虚析构函数。
上篇介绍了虚拟继承如何解决菱形继承的二义性问题。但虚拟继承并非“免费午餐”——它引入了更复杂的内存布局和运行时的访问开销。本篇深入虚拟继承的内部实现:虚基类表(vbtable)如何工作、对象布局是怎样的、构造/析构顺序的特殊规则。更重要的是,我们会讨论:为什么C++社区普遍“不推荐”常规多继承,以及什么时候才真正需要它。
C++11之前,重写虚函数全靠程序员自觉——函数签名写错一点,就不是重写而是隐藏了,编译器一声不吭。C++11引入了两个关键字:override明确标记“我要重写”,让编译器帮你检查签名是否正确;final阻止进一步的继承或重写。本篇讲清楚这两个关键字的用法、场景,以及它们如何让继承体系更安全、更清晰。
让一个类的对象“像函数一样被调用”——这就是仿函数(函数对象)。只需要重载operator(),对象就可以用obj()的语法来调用。仿函数是STL算法的核心组件之一:sort、find_if、for_each等算法都广泛使用仿函数来定制行为。现代C++中lambda表达式本质上就是编译器生成的仿函数。本篇讲清楚仿函数的语法、在STL中的应用,以及与lambda的关系。
自增运算符 ++ 和自减运算符 -- 有前置和后置两种形式。在运算符重载中,如何区分它们?C++的约定是:前置版本无额外参数,返回引用;后置版本有一个 int 占位参数,返回值(通常是副本)。理解这个区别不仅能让你的自定义类型像内置类型一样使用,还能写出更高效的代码——前置比后置少一次临时对象拷贝。本篇讲清楚两种形式的实现方式和选择原则。







