在软件开发领域,C++和C语言都是广泛使用的编程语言,它们各有特点和适用场景。Linus Torvalds曾对C++语言提出了批评,认为它是一个糟糕的语言,并且由于许多水平不高的程序员使用它,导致产生了大量低质量的代码。为了更深入地理解Linus的观点,本文将通过分析Linux代码,探讨C++与C语言在模块化、封装、多态和继承等方面的差异,并讨论如何减少C++代码变更的影响。
模块化是一种软件设计技术,它通过将软件分解成独立的部分来提高软件的可管理性和可维护性。模块化可以通过两种方式实现:
物理模块化:通过使用目录和文件来实现,这种模块化由操作系统提供,并且可以应用于任何语言。在Linux开发中,每个模块都被隔离在不同的目录中,每个文件包含与特定功能相关的结构体、变量和方法。
逻辑模块化:通过使用命名空间、组件、类、结构体和函数来实现,这种技术依赖于语言的能力。C++可以使用命名空间和类来模块化代码,这些类型由语言提供,而不是依赖于目录。
逻辑模块化的优点在于提高了代码的可读性,因为可以更容易地理解和使用代码,而不需要知道代码元素的物理位置。
封装是C++中定义的一个过程,它将数据和函数组合成一个称为类的单元。使用封装方法,程序员不能直接访问数据,数据只能通过类内部的函数访问。
对于C语言,也可以采用物理封装方法,如在模块化部分所述,一个类可以是一个包含函数和数据的文件,可以通过使用“static”关键字来限制函数和变量的可访问性。
封装的优点在于提高了代码的可读性,C语言是低级别的,使用物理方法而不是逻辑方法。
多态意味着某些代码、操作或对象在不同上下文中的行为不同。这种技术在C++项目中非常常用,但对于过程式语言,如C语言,可以使用“switch”、“if”或“goto”等关键字来模拟多态行为,但这种方法往往会增加代码的循环复杂度。
例如,Linux中的一个复杂函数w9968cf_v41_ioctl使用一个大的switch语句来区分依赖于特定命令的行为,而C++可以使用多态和命令模式来简化这段代码的复杂性。
多态的优点在于可以将特定行为隔离到一个类中,从而提高代码的可读性。
Linux主要使用结构体来定义函数操作的数据。如果一个结构体有与其他结构体相同的公共数据,例如,许多结构体可以被认为是“inode”,并添加了一些其他字段,在这种情况下,使用的是聚合而不是继承。
继承可以提高数据的理解,但使用时要小心,它只用于“是”关系。继承意味着高耦合,因此任何更改都可能影响大量代码。
C++提供了更好的可读性,但任何更改或重构都可能很困难。Linus在同一个帖子中谈到了设计变更的想法:“低效的抽象编程模型,两年后发现某个抽象并不是很有效,但现在所有代码都依赖于围绕它的所有漂亮的对象模型,不能修复它而不重写应用程序。”
但是,进行重构需要理解现有代码和设计,然后才能进行更改。C程序很难理解但容易更改,然而C++可能比C更可读,但在进行更改时需要一些努力。
// C语言模块化示例
#include "module1.h"
#include "module2.h"
int main() {
// 使用module1和module2中的功能
module1_function();
module2_function();
return 0;
}
// C++逻辑模块化示例
namespace Module1 {
void function() {
// 实现细节
}
}
namespace Module2 {
void function() {
// 实现细节
}
}
int main() {
Module1::function();
Module2::function();
return 0;
}