开启C++新世界:从函数到对象的两天思维跃迁
1. C 与 C++ 的本质区别
首先,我们要明确,C++ 不是一个“更好的C”,而是一门支持多种编程范式(尤其是面向对象)的全新语言。
编程思想:C语言是面向过程的,核心是函数,我们思考的是“一步一步做什么”。而C++是面向对象的,核心是类和对象,我们思考的是“谁(对象)能做什么事”。
核心特性:C++ 在C的基础上,引入了面向对象的三大特性:封装、继承、多态。同时增加了引用、模板、STL标准库等强大功能,更适合构建复杂的大型项目。
内存管理:C语言使用 malloc 和 free 管理堆内存。C++ 除了兼容它们,更推荐使用 new 和 delete,因为它们能自动调用对象的构造函数和析构函数,确保对象的正确初始化和清理,更加安全。
2. 面向对象(OOP)的魅力
面向对象是C++的灵魂,它的三大特性为代码带来了前所未有的优势:
封装 (Encapsulation):将数据(属性)和操作数据的方法(函数)捆绑在一个“类”中,并隐藏内部细节,只对外提供公共接口。这极大地降低了代码的耦合性并提升了安全性。
继承 (Inheritance):允许子类继承父类的属性和方法,从而实现代码复用。子类还可以在此基础上进行功能扩展或重写,减少重复代码。
多态 (Polymorphism):通过虚函数实现“同一接口,不同行为”。它允许我们使用父类的指针或引用来调用子类的具体实现,极大地提高了程序的灵活性和可扩展性。
3. C++ 的强大工具:std::string
告别了C语言中繁琐的 char* 操作,C++ 提供了强大的 string 类。它完美体现了“封装”的思想,将字符数组和各种操作它的函数打包在一起。
以下是一些关键的 string 操作:
容量与大小
size() / length(): 返回字符串中当前实际的字符数(两者功能完全相同)。
capacity(): 返回在不重新分配内存的情况下,字符串最多能容纳的字符数。capacity() 通常大于或等于 size()。
添加与插入
push_back(char c): 在字符串末尾添加一个字符。
append(const string& str): 在字符串末尾追加另一个字符串。
insert(int pos, const string& str): 在指定位置 pos 插入一个字符串。
其他常用操作
swap(string& other): 交换两个字符串的内容。
replace(int pos, int len, const string& str): 将从 pos 开始的 len 个字符替换为新字符串 str。
4. 类的基石:访问权限
在C++中,类(class)是构建对象蓝图的核心。与C的结构体(只能包含变量)不同,C++的类可以同时包含成员变量和成员函数。
为了实现封装,C++ 提供了三个访问权限关键字:
public:公有成员。在类的内部和外部都可以访问。通常用于定义类的对外接口(函数)。
protected:保护成员。在类的内部和其子类中可以访问,但在类的外部无法访问。
private:私有成员。只能在类的内部访问。通常用于定义类的内部状态(成员变量)。
最佳实践编码规范:
所有成员变量都应设为 private。
需要对外开放的接口函数设为 public。
不希望外部访问的内部辅助函数设为 private 或 protected。
通过 public 的 getter/setter 函数来间接、安全地访问 private 成员变量。
5. 对象的生与死:new 与 delete
对象的创建分为两种方式:在栈上和在堆上。
栈(Stack):MyClass obj; 这样创建的对象位于栈上,生命周期随其作用域结束而自动结束,内存由系统自动管理。
堆(Heap):MyClass* ptr = new MyClass; 使用 new 关键字创建的对象位于堆上,生命周期由程序员手动控制,必须通过 delete ptr; 来释放,否则会造成内存泄漏。
new 和 delete 不仅仅是分配/释放内存,它们会分别调用类的构造函数和析构函数,这是它们与 malloc/free 的根本区别。
6. 深入理解 sizeof(Class)
一个类的对象到底占用多少内存?这取决于以下规则:
空类/空结构体:在C++中占 1个字节,以确保每个对象在内存中有唯一的地址。
成员函数:普通成员函数和静态成员函数都不占用对象的内存空间,它们存储在代码区。
静态成员变量:不占用对象的内存空间,它属于整个类,存储在全局/静态区。
普通成员变量:对象的大小只由普通成员变量决定,并且会遵循内存对齐规则(与C结构体相同)。
一个有趣的点:sizeof 是一个编译时运算符,它括号内的表达式并不会被真正执行。例如,int num = 10; sizeof(++num); 执行后,num 的值仍然是 10。
7. 共享的记忆:static 成员
static 关键字用于创建属于整个类而不是某个特定对象的成员。
静态成员变量 (static int m_num;)
共享:被该类的所有对象共享。任何一个对象修改了它,其他对象看到的值都会改变。
初始化:必须在类的外部进行初始化。
生命周期:在程序整个运行期间都存在。
静态成员函数 (static void func();)
限制:它不能直接访问非静态成员(变量或函数),因为它不与任何特定对象绑定,没有 this 指针。
访问:可以访问静态成员变量或其他静态成员函数。
调用:可以通过类名直接调用(如 MyClass::func();),也可以通过对象调用。
示例:
想象一个类来追踪创建了多少个对象。
class Counter {
public:Counter() { s_objectCount++; // 每次创建对象,共享的静态变量+1m_id = s_objectCount; // 每个对象有自己独有的id}void display() {cout << "I am object #" << m_id << endl;cout << "Total objects created: " << s_objectCount << endl;}private:int m_id; // 普通成员变量,每个对象一份static int s_objectCount; // 静态成员变量,所有对象共享
};// 必须在类外初始化静态成员变量
int Counter::s_objectCount = 0; ```### 结语
我们已经从C的结构化思维迈入了C++面向对象的广阔天地。理解了类、对象、封装、内存管理以及 `static` 的概念,就等于为后续学习继承、多态等更高级的主题打下了坚实的地基。继续前进!