一、类的基本属性
1. 类的定义
类是用class关键字定义的用户自定义类型,可以包含成员变量和成员函数。
2. 代码示例
class A { // 成员变量 int _a; // 成员函数 void func() {} };3. 类的成员
3.1成员变量(类内部的变量)
成员变量一般加
_前缀,与函数参数做区分
3.2 成员函数(类内部的函数)
在类体内定义的成员函数,编译器会隐式视为内联函数(但最终是否内联由编译器决定)
4.类的内存分配
| 成员类型 | 是否占对象内存 | 说明 |
|---|---|---|
| 成员变量 | 占 | 创建对象时分配,对齐规则与结构体相同 |
| 成员函数 | 不占 | 代码存在代码段,对象中不存储 |
| 空类(无成员变量) | 占 1 字节 | 用于占位,标识对象存在 |
5. 类域
类域用于区分不同类之间的成员
头文件里放类的声明,在对应的
.cpp文件中定义成员函数时,需要用类名::指明函数属于哪个类 .例如:void Stack::init() { }
6. 与struct 的区别
struct在 C++ 中也可以定义类区别:
class默认访问权限为private,struct为public
二、对象创建
1. 概念
类名 + 变量名
2. 代码示例
A a;三、访问限定符(public / private)
1. 概念
决定这个成员能不能被外界访问
2. 代码示例
class A { public: void func(); // 类外可调用 private: int _a; // 类外不可访问 };3. 特性
public:类内外都能访问,通常放成员函数private:只有类内部能访问,通常放成员变量protected:目前和private一样(继承时才有区别)限定符作用域从它开始到下一个限定符结束
class默认private,struct默认public
4. 补充
一般public写的是成员函数,private写的是成员变量
四、构造函数
1. 概念
函数名与类名相同,无返回值,用于初始化类的对象
2. 代码示例
class Date { public: Date(int y, int m, int d) { _year = y; _month = m; _day = d; } private: int _year; int _month; int _day; };3. 特性
可以重载,可以有缺省参数
一旦用户写了任何构造,系统不再生成默认构造
调用默认构造不加括号:
Date d;- 三种默认构造
类型 形式 何时生成/调用 无参构造 Date() {}用户显式写出 全缺省构造 Date(int y=1, int m=1, int d=1) {}用户显式写出 编译器默认生成 用户没写任何构造时 对内置类型不初始化(值不确定),对自定义类型调用其默认构造
注意:
在使用默认构造时,用Data t=Data();这样的形式初始化时会调用变量的值初始化,比如int为0,自定义变量调相应的初始构造;用Data t;这样的形式会用随机值。
若使用自己的构造函数,有缺省值的话,Data t;这样的形式会用缺省值
五、析构函数
1. 概念
~类名,无返回值无参数,是对象的销毁
2. 代码示例
class A { public: ~A() { // 释放资源 } };3. 特性
没有动态内存时默认析构足够,当有动态内存时要手动释放
析构顺序与构造相反,后创建的先销毁
六、初始化列表
1. 概念
冒号开头,逗号分隔,在构造函数体之前执行
2. 代码示例
class Date { public: Date(int y, int m, int d) : _year(y), _month(m), _day(d) {} private: int _year; int _month; int _day; };3. 特性
初始化顺序按声明顺序,建议列表顺序与之相同(易错点)
效率比函数体内赋值高
成员类型 是否必须在初始化列表初始化 原因 const成员必须 const变量只能初始化,不能赋值引用成员 必须 引用必须绑定到对象,且不能重新绑定 没有默认构造的对象成员 必须 无法在函数体内构造(没有默认构造可用) 普通内置类型 可选 可以在函数体内赋值,但列表效率更高
七、this 指针
1. 概念
指向当前对象的指针
2. 代码示例
class A { public: void set(int a) { this->_a = a; } private: int _a; };3. 特性
区分同名参数和成员变量:
this->_a = a;this是指针常量,不能修改指向静态成员函数没有
this每个非静态成员函数都有一个隐含的
this指针,指向调用对象
八、拷贝构造
1. 概念
构造函数的重载,参数是同类对象的const引用,用已有对象初始化新对象时调用
2. 代码示例
class Date { public: Date(const Date& d) { _year = d._year; _month = d._month; _day = d._day; } private: int _year; int _month; int _day; };3. 特性
必须用引用,否则无限递归
如果不写,编译器生成默认拷贝构造(浅拷贝)
写法 是否调用拷贝构造 说明 Date d2(d1);调用 直接初始化 Date d2 = d1;调用 拷贝初始化(编译器可能优化为直接构造) func(d1)(传值参数)调用 实参拷贝给形参 return d1(返回值)调用 局部对象拷贝给返回值(可能被 RVO 优化掉) Date d2; d2 = d1;不调用 这是赋值重载,不是拷贝构造
九、浅拷贝 vs 深拷贝
1. 概念
浅拷贝拷贝地址,深拷贝拷贝内容
2. 代码示例
// 浅拷贝(默认) // String s2(s1); // s1 和 s2 的 _data 指向同一块内存 // 深拷贝 String(const String& s) { _data = new char[strlen(s._data) + 1]; strcpy(_data, s._data); }3特性
| 对比项 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 实现方式 | 编译器默认生成 | 用户手动实现 |
| 拷贝内容 | 逐字节拷贝成员变量的值 | 拷贝指针指向的内容,并开辟新内存 |
| 指针成员 | 只拷贝地址(指针的值) | 拷贝指针指向的数据,新对象拥有独立内存 |
| 多个对象的关系 | 多个对象指向同一块内存 | 每个对象有自己的内存,互不干扰 |
| 资源释放 | 多次释放同一块内存 → double free | 各自释放自己的内存,安全 |
| 适用场景 | 没有动态内存成员的简单类 | 类中有指向动态内存的指针成员(如char*、int*) |
| 是否可依赖默认 | 不可依赖(有指针时) | 必须自己实现 |