(一)面向对象的概念
面向对象编程是一种编程范式,它以对象为核心来组织程序结构。对象就是在现实世界中,某个具体的实体在计算机世界中的映射和体现。在 C++ 中,对象是类的实例,类是一种用户自定义的数据类型,它封装了数据(成员变量)和操作这些数据的函数(成员函数)。
比如:银行中实体的柜员,可以进行分析,并将其概念化为具有工号、姓名、性别等状态,和具有存款取款等行为的集合。在C++中就可以设计一个class类,再通过实例化对象,模拟现实中不同的柜员。
(二)状态和行为是对象的主要属性
成员变量是对象的属性(变量、指针数组等),属性的值确定对象的状态。。例如,在一个 汽车对象中,汽车的颜色、当前速度、燃油量等都是汽车对象的状态。
成员函数是对象的方法,确定对象的行为。以汽车为例,汽车的启动、加速、刹车、转弯等操作都是汽车对象的行为。
(三)类的设计与实例化对象
1、类的设计
class Student
{
public:
// 公共成员变量
string student_id;
// 构造函数
Student(const string& name, int age, const string& student_id)
: name(name), age(age), student_id(student_id) {}
void getDetails() const
{
cout << "Name: " << name << ", Age: " << age << ", Student ID: " << student_id <<
endl;
}
protected:
// 受保护的成员变量
int age;
private:
// 私有成员变量
string name;
};
其中“class类名” 称为类头,花括号中的部分称为类体,类体中定义了类成员表。
public protected private是三种重要的访问修饰符,它们用于控制类成员的访问权限:
-
public(公共):public可以被类的任何外部代码访问。这意味着,无论是同一个文件中的其他函数,还是其他文件中的代码,只要能够访问到该类的对象,就能访问其public成员。
-
protected(受保护):protected成员只能被当前类及其派生类(子类)的成员函数访问。这提供了一种机制,使得某些成员可以在类的内部和继承层次结构中被更广泛地使用,而不会被类的外部直接访问。
-
private(私有):private成员只能在当前类内部访问,包括该类的成员函数和其他private成员。这种限制确保了对象的某些部分只能通过类提供的公共接口(通常是public成员函数)来访问,从而实现了封装和数据隐藏。
2、对象的创建与使用
int main() {
// 创建一个学生对象
Student student1("Alice", 20, "S12345");
// 获取并打印学生详情
student1.getDetails();
//直接打印ID
cout << "Student ID: " << student1.student_id << endl;
return 0;
}
上述代码创建了Student类的一个对象student1同时为它分配了属于它自己的存储块,用来存放数据和对这些数据实施操作的成员函数,对象只在定义它的域内有效。
3.C++对象模型
各对象的内存分为:安放成员数据的数据区和安放成员函数的代码区,他们拥有独立的数据区,但代码区是公共的,这样做大大节省了内存。
(四)this指针
对于同一类的不同的对象,编译器在执行成员函数时,是如何知道处理的是哪个对象的数据的?
编译器对程序员自己设计的类型分为三次编译:
1.识别和记录类体中属性的名称,类型和访问限定,如属性在类体中的类型无关,如Student的ID。
2.识别和记录类体中函数原型(返回类型+函数名+参数列表),形参的默认值,访问限定,但不识别函数体。
3.改写在类中定义函数的参数列表和函数体,改写对象调用成员函数的形式。
class Int
{
private:
int val;
public:
void SetVal(int x)
{
this->val = x;
}
int GetVal() const
{
return val;
}
};
改写后会成为:
void SetVal(int x) // 在编译时会改写为:void SetVal(Int * const this , int x)
int GetVal() const // int GetVal(const Int * const this )
(五)构造函数与析构函数
构造函数是一种特殊的成员函数,用于初始化对象。当创建类的实例(对象)时,构造函数会自动被调用。
特点:
-
构造函数的名称与类名相同。
-
构造函数没有返回类型,即使是
void
也不写。 -
构造函数在创建对象时自动调用,无需手动调用。
-
一个类可以有多个构造函数,这些构造函数可以有不同的参数列表,以实现不同的初始化方式。
-
构造函数可以使用初始化列表来初始化成员变量,这是一种更高效的初始化方式。
class Int
{
private:
int val;
public:
Int()//都带有this指针 无返回类型,有返回值,返回值就是它自己
{
val = 0;
cout << "call Int()" << endl;
}
Int(int x )
{
val = x;
cout << "call Int(int x)" << endl;
}
};
构造函数的用途:1.创建对象 2.初始化对象中的属性 3.类型转换。
类型转化的例子:
int main()
{
int x = 10;
Int a(20);
a = x;//先Int x(10),赋给a后,x析构掉 (必须是单参)
return 0;
}
析构函数是另一个特殊的成员函数,用于释放对象占用的资源。当对象的生命周期结束时(例如,对象离开作用域或被显式删除),析构函数会自动被调用。
特点:
-
析构函数的名称是类名前加上波浪号(~)。
-
析构函数不接受任何参数。
-
析构函数没有返回类型,即使是
void
也不写。 -
析构函数在对象的生命周期结束时自动调用,无需手动调用。
-
析构函数可以是虚函数,这在处理基类指针指向派生类对象时非常重要。通过将基类的析构函数声明为虚函数,可以确保在删除基类指针时调用正确的析构函数(即派生类的析构函数)。
class Int { private: int val; public: Int()//都带有this指针 无返回类型,有返回值,返回值就是它自己 { val = 0; cout << "call Int()" << endl; } Int(int x ) { val = x; cout << "call Int(int x)" << endl; } ~Int()//无返回类型,有返回值,返回值是地址 { cout << "Desroy" << endl; } };