C++第二讲:类和对象(上)
一、类的定义(核心)
1. 类的基本格式
cpp
class 类名
{
public:
// 成员函数(给外部用的接口)
private:
// 成员变量(数据,不希望外部直接改)
}; // 必须加分号!!!
-
class:定义类的关键字
-
成员变量:属性(数据)
-
成员函数:方法(操作数据的行为)
命名习惯
成员变量通常加下划线区分:
cpp
int _year; // 推荐
int year_;
int m_year;
2. struct 在 C++ 里也能定义类
C++ 升级了 struct:
-
里面可以写函数
-
直接用 struct 名当类型,不用 typedef
-
默认访问权限是 public,class 默认是 private
cpp
struct Node
{
void Init(int x)
{
_val = x;
_next = nullptr;
}
int _val;
Node* _next;
};
二、访问限定符(封装核心)
C++ 用 3 个权限控制访问:
| 关键字 | 作用 |
|---|---|
| public | 类外可以直接访问 |
| private | 类外不能直接访问 |
| protected | 类外不能访问(继承才有用) |
规则
-
class 默认 private ,struct 默认 public
-
作用域:从当前限定符开始,到下一个限定符 / 类结束
-
规范写法:
-
成员变量 → private
-
成员函数 → public
-
三、类域与声明定义分离
1. 类域
类本身就是一个作用域 ,外面使用必须用 :: 指明属于哪个类。
2. 类外定义成员函数
cpp
class Stack
{
public:
void Init(int n = 4); // 声明
private:
int* _a;
size_t _top;
size_t _capacity;
};
// 类外定义:必须写 类名::函数名
void Stack::Init(int n)
{
_a = (int*)malloc(sizeof(int) * n);
_top = 0;
_capacity = n;
}
四、实例化(最重要的概念)
1. 什么是实例化
-
类 = 设计图(不占内存,只是声明)
-
对象 = 盖出来的房子(占内存,存数据)
cpp
Date d1; // 用 Date 类实例化出 d1 对象
Date d2; // 一个类可以实例化多个对象
2. 对象大小计算
结论:
对象只存成员变量,不存成员函数!
-
成员函数存在代码段,所有对象共用
-
对象大小 = 成员变量总大小 + 内存对齐
-
空类大小 = 1 字节(占位,表示对象存在)
内存对齐规则(和结构体一样)
-
第一个成员从偏移 0 开始
-
其他成员对齐到:min (默认对齐数,类型大小) 的整数倍
-
VS 默认对齐数:8
-
总大小是最大对齐数的整数倍
五、this 指针(C++ 灵魂)
1. 是什么
成员函数里隐藏的第一个参数,类型是:
cpp
类名* const this
-
编译器自动加,不能手动写在形参 / 实参
-
指向当前调用函数的对象
-
函数里访问成员变量,本质都是:
cppthis->_year = year;
2. 特性
-
this 不能被修改(const 修饰)
-
this 存在栈上(不是对象里)
-
调用时自动传对象地址:
cppd1.Init(2024, 5, 1); // 编译器转为:Init(&d1, 2024,5,1);
3. 两道必考题(一定要会)
题 1
cpp
class A
{
public:
void Print()
{
cout << "Print" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print(); // 运行结果?
}
✅ 正常运行
原因:没访问成员变量,不需要解引用空指针。
题 2
cpp
class A
{
public:
void Print()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print(); // 运行结果?
}
❌ 运行崩溃
原因:访问了 this->_a,但 this 是空指针。
六、C 与 C++ 实现栈对比(理解封装)
C 语言
-
数据和函数分离
-
外部可直接修改结构体成员
-
每次调用必须传指针
ST* ps
C++
-
数据 + 函数封装在类里
-
变量 private,外部不能乱改
-
自动传 this 指针,不用手动传对象地址
-
代码更简洁、更安全
七、快速上手完整示例(跟着敲)
cpp
#include <iostream>
#include <cstdlib>
#include <cassert>
using namespace std;
class Stack
{
public:
// 初始化
void Init(int n = 4)
{
_a = (int*)malloc(sizeof(int) * n);
assert(_a);
_top = 0;
_capacity = n;
}
// 入栈
void Push(int x)
{
if (_top == _capacity)
{
_capacity *= 2;
_a = (int*)realloc(_a, sizeof(int) * _capacity);
assert(_a);
}
_a[_top++] = x;
}
// 取栈顶
int Top()
{
assert(_top > 0);
return _a[_top - 1];
}
// 出栈
void Pop()
{
assert(_top > 0);
--_top;
}
// 销毁
void Destroy()
{
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
int* _a;
size_t _top;
size_t _capacity;
};
int main()
{
Stack st;
st.Init();
st.Push(1);
st.Push(2);
st.Push(3);
cout << st.Top() << endl; // 3
st.Pop();
cout << st.Top() << endl; // 2
st.Destroy();
return 0;
}
八、本节必须背会的 7 句话
-
类是设计图,对象才占内存
-
对象只存成员变量,不存成员函数
-
访问权限:public 对外,private 对内
-
类外定义函数必须加 类名::
-
this 指针是隐藏的第一个参数,指向当前对象
-
this 不能修改,存在栈里
-
空类大小是 1 字节