北京交通大学《面向对象程序设计与C++》课程学习笔记
目录
一、认识面向对象
1.什么是面向对象
面向对象(Object Oriented)是一种软件开发方法,一种编程范式。面向对象的概念和应用已超越了程序设计与软件开发,扩展到如应用结构、应用平台等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
简而言之,面向过程就是根据业务从上到下写代码,而面向对象就是将数据和函数绑定到一起,加速开发程序,减少重复的代码的重写过程。
2.类与对象
面向对象程序设计应用以对象作为基本元素的方法,用计算机语言描述并处理一个问题
对象的定义
- 对象可以是人们要研究的任何事物,包括具体的(如程序、计算机)和抽象的(如思想、规则、计划等)
- 每一类对象都有属性(如大小、形状、重量等)和行为(如行走、转弯等)
类的定义
- 同类对象公共的属性和行为
类与对象的关系
- 类是具有相同数据结构(属性)和相同操作功能(行为)的对象的集合,它规定了这些对象的公共属性和行为方法
- 对象是类的一个实例,例如,汽车是一个类,而行驶在公路上的一辆汽车则是一个对象
例如:
class CStudent {
private: //学生的属性
char mNo[9]; // 学号,9位字符数组
char* mpName; // 姓名指针
int mScore[5]; // 五门功课成绩
static int mCount; // 静态成员变量,用于计数学生对象数量
public: //学生的行为(方法)
void SetStudent(const char* name, int scores[5]); // 设置学生信息
void ShowStudent() const; // 显示学生信息
};
3.面向对象的基本特征
抽象性
- 抽象是指对一类对象进行概括,抽出他们共同的性质并加以描述的过程
封装性
- 封装是将抽象得到的属性数据和行为代码结合,同时,封装避免了外部与对象之间的影响(对象无法影响外部数据,外部对对象的修改只能通过public方法)
class CStudent {
private: //学生的属性
char mNo[9]; // 学号,9位字符数组
char* mpName; // 姓名指针
int mScore[5]; // 五门功课成绩
static int mCount; // 静态成员变量,用于计数学生对象数量
public: //学生的行为(方法)
void SetStudent(const char* name, int scores[5]); // 设置学生信息
void ShowStudent() const; // 显示学生信息
};
在上述代码中,private中的数据外部无法访问,但是可通过public中的函数(外部接口)来达到访问的目的
继承性
- 继承是指一个新类可以从现有的类派生而来,很好地解决了软件的可重用性问题
多态性
- 多态是指类中具有相似功能的不同函数使用同一个名称来实现,并且允许不同类的对象对同一消息做出不同的响应
二、C++类
1.C++类的定义与实现
C++类的定义
- C++将对象的属性抽象为数据成员,将对象的行为抽象为成员函数。数据成员又称成员变量,成员函数又称方法
C++类的实现
class < 类名 > {
private:
< 私有数据成员与私有成员函数的声明列表 >;
public:
< 公有数据成员与公有成员函数的声明列表 >;
protected:
< 保护数据成员与保护成员函数的声明列表 >;
};
例如:
//CStudent.h
class CStudent {
private:
char mNo[9]; // 学号,9位字符数组
char* mpName; // 姓名指针
int mScore[5]; // 五门功课成绩
static int mCount; // 静态成员变量,用于计数学生对象数量
public:
CStudent(); // 默认构造函数
CStudent(const CStudent& zS); // 拷贝构造函数
};
2.构造函数与析构函数
成员变量初始化
- 在定义类时不能对成员变量进行初始化,因为无法确定成员变量属于哪一个对象。成员变量一般都定义为私有属性,也不能在声明对象后利用赋值运算对成员变量进行初始化。成员变量的初始化一般是利用一个名为构造函数的成员函数来完成
构造函数的定义
- 构造函数是一种特殊的成员函数,它是在创建对象时(声明或用new动态创建)系统自动调用的成员函数
析构函数的定义
- 析构函数也是一种特殊的成员函数,它是在对象生存期结束时系统自动调用的成员函数
构造函数名称与类名相同,析构函数名称必须在类名前加上" ~ "符号
例如:
//构造函数
CStudent::CStudent()
{
mCount++; //每次创建学生 计数加一
sprintf(mNo,"1728%04d",mCount); //按照计数设置学号
mpName = NULL; //姓名指针置空
memset(mScore,0,sizeof(mScore)); //清空成绩数组
}
//析构函数
CStudent::~CStudent()
{
delete[] mpName;
}
析构函数在运行时遵循“先进后出,后进先出”的原则 (类比数据结构中的栈)
拷贝构造函数
- 拷贝构造函数的参数是本类对象的一个引用
- 若未定义拷贝构造函数,编译系统自动为类添加一个默认的拷贝构造函数
- 默认拷贝构造函数采取浅拷贝
浅拷贝:
- 只进行基本数据类型的拷贝
- 当数据成员为指针类型时,存在潜在危险,即两个对象的指针指向同一内存区域
例如:
//构造函数
//CStudent::CStudent() { ... }
//拷贝构造函数
CStudent::CStudent(const CStudent& zS)
{
strcpy(mNo, zS.mNo); // 复制学号
mpName = new char[strlen(zS.mpName) + 1];
strcpy(mpName, zS.mpName); // 深拷贝姓名
for (int i = 0; i < 5; i++)
{
mScore[i] = zS.mScore[i]; // 复制成绩数组
}
}
//析构函数
//CStudent::~CStudent() { ... }
this指针
-
this指针是一个指向当前对象的特殊指针
-
每个非静态成员函数隐藏有一个this指针的函数参数,当通过一个对象调用函数时,编译器将把当前对象的地址传递给this指针
例如:
//用户输入的代码
void CTime::showTime {
cout << hour << minute << second << endl;
}
//编译器处理的代码
void CTime::showTime(CTime* const this) {
cout << this->hour << this->minute << this->second << endl;
}
CTime t1(11, 30);
t1.showTime(); //用户输入的代码
t1.showTime(&t1) //编译器处理的代码
三、静态成员
1.静态数据成员
关于类的属性
- 不同对象具有不同的属性值
- 所有对象具有相同的属性值
- 类属性的声明:
static < 数据类型 >< 静态成员名 >
初始化时机
- 实例属性:对象创建时,构造函数
- 类属性:所有类共享,类外部初始化
< 数据类型 >< 类名 >::< 静态数据成员名 > = < 初始值 >
例如:
class Railway {
public:
Railway(const std::string& name, int length) : railwayName(name), railwayLength(length) {
// 每创建一个对象,铁路总长度累加
totalLength += length;
}
void displayInfo() const {
std::cout << "铁路名称: " << railwayName << ", 长度: " << railwayLength << " 公里" << std::endl;
}
static int getTotalLength() {
return totalLength;
}
private:
std::string railwayName;
int railwayLength;
// 静态数据成员,用于记录所有铁路的总长度
static int totalLength;
};
// 初始化静态数据成员
int Railway::totalLength = 0;
2.静态成员函数
-
静态成员函数也与一个类相关联,而不是只与一个特定的对象相关联
-
静态成员函数只能访问类的静态成员(成员变量与成员函数),而不能访问类的非静态成员
-
静态成员函数访问非静态成员的方法:将对象作为静态成员函数的参数 (不建议)
-
既要访问静态成员,又要访问非静态成员,建议使用普通成员函数
-
区别于非静态成员函数,静态成员函数没有 this 指针,因为类的静态成员函数只有一个运行实例
例如:
class Train {
public:
// 构造函数,用于初始化列车信息
Train(const std::string& name, int speed, int capacity)
: trainName(name), trainSpeed(speed), passengerCapacity(capacity) {
// 每创建一辆列车,将其信息添加到静态成员变量 allTrains 中
allTrains.push_back(this);
}
// 静态成员函数,用于显示所有列车的信息
static void displayAllTrains() {
std::cout << "所有列车信息如下:" << std::endl;
for (const auto& train : allTrains) {
train->displayTrainInfo();
}
}
// 普通成员函数,用于显示当前列车的信息
void displayTrainInfo() const {
std::cout << "列车名称:" << trainName << ",速度:" << trainSpeed << " km/h,载客量:" << passengerCapacity << " 人" << std::endl;
}
private:
std::string trainName;
int trainSpeed;
int passengerCapacity;
// 静态数据成员,用于存储所有列车的指针
static std::vector<Train*> allTrains;
};
// 初始化静态数据成员
std::vector<Train*> Train::allTrains;