什么是类
类是一种抽象的数据类型,作为对象的蓝图或模板,它将具有相同属性和行为的对象进行统一抽象封装。其中属性描述对象的特征,如 “汽车” 类中的颜色、品牌等;方法则定义对象可执行的操作,像 “汽车” 类的启动、加速等方法。
什么是对象
对象是类的实例化,是依据类所定义的模板创建出的具体实体。其状态由属性值决定,如某辆具体汽车的红色、宝马等属性值构成其状态;行为通过调用所属类的方法实现,如调用汽车的启动、加速方法展现其行为。
类与对象的关系
类是对象的抽象概括,提取了相似对象的共性形成通用模板,不指向具体实体。而对象是类的具体体现,虽都具有类定义的属性和方法,但属性值不同,状态和行为也各异,如不同汽车对象的属性值及行为表现均有差别。
如何定义一个类
语法:
class 类名
{
成员变量:描述事物的静态特征,一个类中可以有多个成员变量,也可以一个都没有
构造函数:创建对象
析构函数:回收对象
拷贝构造:对象赋值给对象
成员函数:描述事物的动态特征
}
如:
#include <iostream>
#include <string>// 定义Person类
class Person {
public:
std::string name; // 成员变量,用于存储人的姓名
int age; // 成员变量,用于存储人的年龄// 成员函数,用于设置人的姓名和年龄
void setInfo(const std::string& n, int a) {
name = n;
age = a;
}// 成员函数,用于输出人的信息
void showInfo() {
std::cout << "姓名:" << name << ",年龄:" << age << std::endl;
}
};int main() {
// 创建一个Person类的对象p1
Person p1;
// 使用对象p1调用成员函数setInfo来设置信息
p1.setInfo("小明", 20);
// 使用对象p1调用成员函数showInfo来展示信息
p1.showInfo();return 0;
}
注意:
因为类的定义只需定义一次,所以我们一般将其写在头文件中
但是类中有成员函数,头文件中对函数只声明不实现
所以在头文件中定义类,在其对应的源文件中实现其类的成员函数
如何创建一个对象
语法:
类名 对象名;
对象的使用:
获取成员变量的值
对象名.成员变量名
修改成员变量的值
对象名.成员变量名 = 值;
调用成员函数
对象名.成员函数名(实参列表)
注意:
一个类可以创建多个对象
多个对象之间互不打扰
访问权限修饰符
作用:
限定类中的成员使用范围
访问权限修饰符:
public:程序任何一处可直接使用
protected:当前类中或子类中使用
private:当前类中使用
使用:class 类名
{
private:
成员
public:
成员
protected:
成员
}
类的设计
私有化成员变量
通过将成员变量设为私有,限制外部直接访问,就像给数据加锁,仅类内可操作,避免外部随意更改致数据混乱,增强类及程序的稳定性与可维护性,比如 “员工” 类里工资变量私有化的情况。
公共成员函数
把成员函数设为公共来构建类与外部交互的接口,外部按规定调用函数让类执行任务,无需知晓内部实现细节,能降低类间耦合、提高代码模块化程度,像 “图形” 类中绘制、算面积等公有函数便于协同工作。
提供 get 与 set 函数
因成员变量私有化,外部需获取和修改值时,get 函数用于返回私有变量值,告知外部其状态;set 函数接收外部值,经合法性检查后赋给私有变量,间接实现修改,如 “学生” 类里成绩、年龄变量对应的操作。
this关键字
概念:
this 是一个指针,它所指向的对象取决于调用 this 所在函数的对象,也就是说,谁调用了这个函数,this 就代表谁。
作用:
1,在当前类中调用当前类的成员,此时this可以忽略不写
2,当局部变量与成员变量重名时
变量名 局部变量
this->变量名 成员变量
如:
#include <iostream>
class Person {
public:
std::string name;
int age;void setName(const std::string& newName) {
this->name = newName;
}void setAge(int newAge) {
this->age = newAge;
}void showInfo() {
std::cout << "姓名: " << this->name << ", 年龄: " << this->age << std::endl;
}
};int main() {
Person p;
p.setName("小明");
p.setAge(20);
p.showInfo();return 0;
}
构造函数
作用:创建本类对象时调用
语法:
类名(形参列表)
{
函数体
}
调用:
调用无参构造:
类名 对象名;
调用有参构造:
类名 对象名(实参列表);
注意:
1,如果一个类中没有自定义构造函数,系统将为其提供一个无参构造
2,如果一个类中有自定义构造函数,系统将不会为其提供无参构造函数
3,一个类中可以有多个构造函数,这多个构造函数的关系是重载
析构函数
作用:当对象被销毁时调用
语法:
~类名()
{
函数体
}
注意:
一个类中只能写一个析构函数
如果不写,系统为其提供一个默认的析构函数
拷贝构造
作用:此类对象A赋值给此类对象B 会触发拷贝构造
类名 对象名A;
类名 对象名B = 对象名A;
语法:
类名(const 类名& 别名)
{
函数体
}
注意:
此时不会触发构造函数
注意浅拷贝,此时一定要进行深拷贝,避免重复释放导致的崩溃
初始化列表
语法:
类名(形参列表):成员变量名(形参中的变量名),成员变量名(形参中的变量名),...
{
函数体
}
注意:
基本类型除外实现的是浅拷贝
如:
#include <iostream>
#include <string>class Person {
public:
std::string name;
int age;// 普通构造函数,用于初始化对象的成员变量
Person(const std::string& n, int a) : name(n), age(a) {}// 拷贝构造函数
Person(const Person& other) {
this->name = other.name;
this->age = other.age;
std::cout << "拷贝构造函数被调用" << std::endl;
}void showInfo() {
std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
}
};int main() {
Person person1("小明", 20);// 这里会触发拷贝构造函数,用person1初始化person2
Person person2 = person1;person1.showInfo();
person2.showInfo();return 0;
}
隐式转换
当调用的构造函数只有一个参数时,可以进行隐式转换。
语法:
类名 对象名 = 实参;
explicit关键字:
作用:进制隐式转换
语法:
explicit 类名(形参)
{ }
new
作用:在堆内存创建对象
语法:
类名 *对象指针 = new 类名;
类名 *对象指针 = new 类名(实参列表);
步骤:
先在堆中开辟内存
再调用构造函数
delete
作用:
释放对象在堆内存占用的空间
语法:
delete 对象指针;
步骤:
先执行析构函数
再释放对象指针指向的内存
类B的对象作为类A的成员变量
创建时构造函数的调用顺序
先成员构造
再自己构造
销毁时析构函数的调用顺序
先自己析构
再成员析构
注意
使用new创建A类对象时,依旧会先创建其成员类B的对象
先成员构造
再自己构造
使用new是在堆中开辟的,无法自动释放,需要使用delete
先自己析构
再成员析构
class B{
public:
char *name = (char *)calloc(50,1);
~B()
{ free(name); }
}
class A{
B b;
}
int mian()
{
A *a = new A;
delete a;
}
对象数组
作用:
存储对象的数组
静态创建:
类名 数组名[长度] = {对象1,对象2,对象.....};
动态创建:
类名 *数组名 = new 类名[]{对象1,对象2,对象...};
注意:
释放语法:
delete [] 数据名;