C++ 中 类 的封装
1.1 封装的声明
C++中对象的类型称为类(class),类代表了某一批对象的共性和特征,类是对象的抽象,而对象是类的具体实例(instance)。
先声明一个类类型,然后用它去定义若干个同类型的对象。对象就是类类型的一个变量。可以说类是对象的模板,是用来定义对象的一种抽象类型。
类是抽象的,不占用内存,而对象是具体的,占用存储空间。在一开始时弄清对象和类的关系是十分重要的。类是用户自己指定的类型。
如果程序中要用到类类型,必须自己根据需要进行声明,或者使用别人已设计好的类。C++标准本身并不提供现成的类的名称、结构和内容。
class 类名{
private:
// 私有的成员变量(属性/数据) 和 成员函数(方法/行为)
protected:
// 受保护的成员变量(属性/数据) 和 成员函数(方法/行为)
public:
// 共有的成员变量(属性/数据) 和 成员函数(方法/行为)
};
1.1.1 类声明示例
设计一个学生类 获取学生的成绩
#include <iostream>
#include <string>
using namespace std;
// 学生类
class stu
{
public: //访问权限 公共的权限
// 成员属性
string name; // 姓名
int id; // 学号
string Class; // 班级
int soc; // 成绩
// 成员函数 - 获取到学生的成绩
void show_soc(void){
cout << name << "的成绩 = " << soc << endl;
}
protected: //访问权限 保护的权限
private: //访问权限 私有的权限
};
int main(int argc, char const *argv[])
{
// 使用类定义变量的过程 我们称为 : 实例化对象
// 实例化对象
stu s_arr[3] = {
{.name = "张1" , .id = 1 , .Class = "1班" , .soc = 59},
{.name = "张2" , .id = 2 , .Class = "1班" , .soc = 59},
{.name = "张3" , .id = 3 , .Class = "1班" , .soc = 59},
};
for (size_t i = 0; i < 3; i++)
{
s_arr[i].show_soc();
}
return 0;
}
1.2 类的声明-访问权限
1.2.1权限的种类
访问控制权限:
-
public: 公共: 修饰的成员 在类内 子类 类外 都可以直接访问
-
protected: 保护: 修饰的成员 在类内 子类 可以直接访问 类外不行
-
private: 私有: 修饰的成员 在内类 可以直接访问 子类 类外 不行
1.2.2 权限间的关系
类内 | 子类 | 类外 | |
---|---|---|---|
public | √ | √ | √ |
protected | √ | √ | × |
private | √ | × | × |
类的成员函数访问权限:
- 类的成员函数可以访问类的所有成员变量,包括
public
、protected
和private
。即使是通过函数传递过来的同类对象的私有成员,也可以访问。
访问控制是针对整个类:
- 访问控制是针对于整个类的,而不是某个具体的类对象。类内所有的成员函数和成员变量都受访问控制权限的影响。
访问控制的作用范围:
- 访问控制权限一旦声明,后面的所有成员都将遵循该权限,直到出现新的访问权限声明,或者类的定义结束。
访问控制声明的简洁性:
- 通常情况下,访问权限只需要在类内声明一次。多次声明是允许的,但不常见。
默认访问权限:
- 如果类中没有明确指定访问控制权限,默认情况下,所有成员都是
private
。
访问控制的目的:
- 访问控制的存在是为了保证类的正确使用。类的设计者通过设置访问权限,防止使用者以不合理的方式操作类的成员。例如,防止圆类的半径被赋值为负数等不合逻辑的操作。
1.3 类的声明-函数定义
在 C++ 中,类的成员函数可以通过两种方式声明和定义:
-
类内声明,类外定义:在类的内部只进行函数的声明,而函数的定义在类的外部完成。
- 通常用于保持类的定义简洁,便于维护较大的程序。
-
类内声明,类内定义:在类的内部同时进行函数的声明和定义。
- 适合简短的函数,能让类的定义更紧凑。
1.3.1类内声明,类外定义
#include <iostream>
using namespace std;
class MyClass {
public:
// 类内声明
void printHllo();
};
// 类外定义
void MyClass::printMessage() {
cout << "Hello" << endl;
}
int main() {
MyClass obj;
obj.printMessage(); // 调用类外定义的函数
return 0;
}
1.3.2 类内声明,类内定义
#include <iostream>
using namespace std;
class MyClass {
public:
// 类内声明和定义
void printHllo() {
cout << "Hello" << endl;
}
};
int main() {
MyClass obj;
obj.printMessage(); // 调用类内定义的函数
return 0;
}
1.4 类示例
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
namespace School{
/**
* 学生类,封装学生姓名、学号和成绩,提供计算平均分和显示信息的方式。
*/
class Student
{
private:
std::string name; // 学生姓名
int id; // 学号
std::vector<int> scores;// 存储成绩
public:
/**
* 构造函数
* @param n - 学生姓名
* @param i - 学号
*/
Student(const std::string & n, int i) : name(n), id(i){ }
/**
* 添加成绩
* @param score - 成绩(0~100 的整数)
* 如果成绩不在范围内, 抛出 std::out_of_range 异常。
*/
void addScore(int score){
if (score >= 0 && score <= 100){
scores.push_back(score);
}else{
throw std::out_of_range("成绩无效, 请输入 0 到 100 之间的分数。");
}
}
/**
* 计算平均分
* @return 平均分
*/
double avgScore() const{
if(scores.empty()){
return 0.0;
}
int total = 0;
for(int s : scores){
total += s;
}
return static_cast<double>(total) / scores.size();
}
/**
* 显示学生信息
*/
void info() const{
std::cout << "姓名: " << name
<< "\n学号: " << id
<< "\n平均分: " << avgScore() << std::endl;
}
};
}
int main(int argc, char const *argv[])
{
School::Student stu("李四", 1001); // 创建学生对象
stu.info();
stu.addScore(85); // 添加成绩
stu.addScore(90);
stu.addScore(78);
stu.info(); // 再次显示信息
try {
stu.addScore(110); // 测试无效成绩
} catch (const std::out_of_range& e) {
std::cerr << e.what() << std::endl;
}
try {
stu.addScore(-5);
} catch (const std::out_of_range& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}