【C++】Chapter01 类与对象
面向过程:关注事件的逻辑性流程
面向对象:关注事件出现的对象
面向对象更高级于面向过程
面向对象的三大特性:封装、继承、多态。
类
类的定义
代码语言:javascript代码运行次数:0运行复制class className
{
// 类体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
- 类体中内容称为类的成员:
- 类中的变量称为类的属性或成员变量;
- 类中的函数称为类的方法或者成员函数;
注:计算对象的大小只计算成员变量大小总和,而不计算函数。
- 类的两种定义方式:
- 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成inline内联函数处理。
image-20250208111224832 - 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名 ::(声明定义分离)
image-20250208111255296
类的访问限定符
- public修饰的成员在类外可以直接被访问(公开)
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)(私密)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
class
的默认访问权限为private,struct
为public(因为struct要兼容C)
封装
封装的定义:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
封装本质上是一种管理,让用户更方便使用类。
对于stack的实现C语言与C++的区别:
从底层来说没有区别。
封装的实现:通过访问限定符的变换,将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。
类的实例化
在类中,成员变量仅仅是被声明而没有被定义;
当我们在其他地方使用这个变量的时候,才会对其进行定义(也就是实例化)
tips:从这里也可以得知声明和定义的区别:声明仅仅是一个抽象化的规定;而定义才是将其实例化,将其变成实际的东西
类对象的存储
内存对齐规则:牺牲空间提高性能
- 结构体的起始地址必须是其最大成员对齐数的整数倍。
- 结构体的总大小必须是最大对齐数的整数倍。如果结构体中嵌套了其他结构体,嵌套的结构体也要对齐到自己的最大对齐数的整数倍处。
// 类中既有成员变量,又有成员函数 占成员变量的字节和,并且遵循内存对齐规则
class A1 {
public:
void f1(){}
private:
int _a;
};
// 类中仅有成员函数 占一个字节,表示成员函数
class A2 {
public:
void f2() {}
};
// 类中什么都没有---空类 占一个字节,用于占位
class A3
{};
this指针
调用同一个函数,但是结果不一样——使用了隐含的this指针。
C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数this,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。
只不过所有的操作对用户是透明的,即用户不需要来传递,编 译器自动完成。
this指针的特性
- this指针类型:
类类型* const
,所以成员函数无法给this指针赋值 - 只能在成员函数的内部使用
- 本质上就是成员函数的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递
构造函数和析构函数
- 问题: 初始化和销毁经常忘记 有些地方写起来很繁琐
- 解决方法:
- 构造函数和析构函数,属于默认成员函数(我们不写,编译器也会自动生成。)
构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,完成对象的初始化。并且在对象整个生命周期内只调用一次。注意:构造函数的主要任务并不是开空间创建对象,而是初始化对象。
构造函数的特点
- 与类名相同,没有返回值(甚至不能写
void
)。 - 在对象创建时自动调用,不需要手动调用。
- 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义,编译器将不再生成。----------------------------也就是说我们不主动去写,构造函数就是自动生成。
- 可以重载(多个构造函数参数不同)。
- 默认构造函数、拷贝构造函数、移动构造函数、委托构造函数等。
- 对于内置类型不做处理;对于自定义类型会去调用它的默认构造。
构造函数的基本用法
1 默认构造函数(无参数)
代码语言:javascript代码运行次数:0运行复制#include <iostream>
using namespace std;
class Person {
public:
string name;
// 默认构造函数(无参数)
Person() {
cout << "默认构造函数被调用!" << endl;
name = "Unknown";
}
void show() { cout << "Name: " << name << endl; }
};
int main() {
Person p; // 自动调用构造函数
p.show();
return 0;
}
输出
代码语言:javascript代码运行次数:0运行复制默认构造函数被调用!//并未显式调用,但是却依旧打印------说明自动调用
Name: Unknown