#include <iomanip>
#include <ios>
#include <iostream>
#include<string>
// write your code here......
#include<vector>
using namespace std;
class Employee {
private:
string name;
double salary;
// write your code here......
public:
Employee(string name, double salary) : name(name), salary(salary){}
string getName() const {
return name; }
double getSalary() const {
return salary; }
double show(){
const int number = 3500;
int mouth_s = salary - number;
double person_s = 0.0;
if(mouth_s>80000){
person_s = mouth_s*0.45-13505;
}else if (mouth_s<=80000 && mouth_s>55000) {
person_s = mouth_s*0.35-5505;
}else if (mouth_s<=55000 && mouth_s>35000) {
person_s = mouth_s*0.30-2755;
}else if (mouth_s<=35000 && mouth_s>9000) {
person_s = mouth_s*0.25-1005;
}else if (mouth_s<=9000 && mouth_s>4500) {
person_s = mouth_s*0.20-555;
}else if (mouth_s<=4500 && mouth_s>1500) {
person_s = mouth_s*0.10-105;
}else if(mouth_s<=1500 && mouth_s>0){
person_s = mouth_s*0.03;
}
return person_s;
}
};
int main() {
// write your code here......
vector<Employee*> ve_p;
ve_p.push_back(new Employee("王五", 100000));
ve_p.push_back(new Employee("李四", 8000));
ve_p.push_back(new Employee("张三", 6500));
for(const auto& p : ve_p ){
cout<<p->getName()<<"应该缴纳的个人所得税是:"<<fixed<<setprecision(1)<<p->show()<<endl;
}
return 0;
}
一、getter函数是什么?(通俗解释+代码示例)
getter函数(也叫「访问器函数」)是类的公有成员函数,核心作用是:让外部代码安全地读取类的私有/保护属性值(因为私有属性外部无法直接访问)。
简单说:把类的属性“锁起来”(设为private),只留一个「只读小门」(getter函数),外部想读属性值,必须走这个小门。
直观对比:无getter vs 有getter
#include <iostream>
#include <string>
using namespace std;
// 示例类:Student(包含name/score两个属性)
class Student {
private:
// 1. 属性私有化(核心:外部不能直接访问)
string name;
int score;
public:
// 构造函数:初始化属性
Student(string n, int s) : name(n), score(s) {}
// 2. getter函数:读取私有属性(命名规范:get+属性名,首字母大写)
string getName() const { // 读取name,const保证函数不修改类成员
return name;
}
int getScore() const { // 读取score
return score;
}
};
int main() {
Student stu("张三", 85);
// ❌ 错误:私有属性外部无法直接访问
// cout << stu.name << endl;
// ✅ 正确:通过getter函数读取属性
cout << "姓名:" << stu.getName() << endl; // 输出:张三
cout << "分数:" << stu.getScore() << endl; // 输出:85
return 0;
}
二、为什么需要getter函数?(核心:封装+安全+可维护)
如果直接把属性设为public(外部能直接读写),虽然写代码快,但会导致数据混乱、代码失控、后期维护难——这违背了面向对象的核心思想「封装」(把类的内部数据和逻辑隐藏,只暴露必要的接口)。
getter函数的核心价值有5点,结合例子讲清楚:
1. 保护数据安全:避免属性被非法篡改/读取
如果属性公有,外部可以随便改,很容易出现不符合逻辑的值(比如分数设为-100);而私有化+getter能严格控制访问:
// 反例:属性公有,数据混乱
class BadStudent {
public:
string name;
int score;
};
int main() {
BadStudent stu("李四", 90);
stu.score = -50; // 非法值!外部可以随便改,类无法阻止
cout << stu.score << endl; // 输出-50,数据完全失控
return 0;
}
2. 控制读取规则:可在getter中加逻辑,返回“合法值”
比如分数是小数(double),但想返回整数;或者隐藏敏感信息(比如姓名只显示首字),只需要改getter函数,外部代码不用动:
class Student {
private:
string name;
double score; // 分数改为小数
public:
Student(string n, double s) : name(n), score(s) {}
// getter加逻辑:分数四舍五入返回整数
int getScore() const {
return (int)(score + 0.5);
}
// getter加逻辑:姓名只显示首字
string getName() const {
return name.substr(0, 1) + "**";
}
};
int main() {
Student stu("张三", 85.6);
cout << stu.getScore() << endl; // 输出86(四舍五入)
cout << stu.getName() << endl; // 输出张**(隐藏敏感信息)
return 0;
}
3. 实现“只读属性”:只给getter,不给setter
如果想让属性“只能读、不能改”(比如学生的入学时间),只提供getter函数,不提供修改属性的setter函数即可:
class Student {
private:
string enrollTime = "2026-01-01"; // 入学时间(固定)
public:
// 只有getter,没有setter → 外部只能读,不能改
string getEnrollTime() const {
return enrollTime;
}
};
int main() {
Student stu;
cout << stu.getEnrollTime() << endl; // 可读:2026-01-01
// stu.enrollTime = "2025-12-31"; // ❌ 私有属性,改不了
// 也没有setEnrollTime函数 → 彻底只读
return 0;
}
4. 提高代码可维护性:内部修改不影响外部
如果后续需要修改属性的存储方式(比如把score从int改成double),只需要修改getter函数的返回逻辑,外部调用的代码完全不用动:
// 版本1:score是int
class StudentV1 {
private:
int score;
public:
int getScore() const { return score; }
};
// 版本2:score改成double,只需改getter
class StudentV2 {
private:
double score; // 内部存储变了
public:
int getScore() const { return (int)score; } // 外部返回值类型不变
};
// 外部调用代码:完全不用改!
void printScore(const StudentV2& stu) {
cout << stu.getScore() << endl; // 不管内部怎么变,调用方式不变
}
5. 符合面向对象设计原则:高内聚、低耦合
类的内部实现(比如属性类型、存储规则)是“内聚”的,对外只暴露统一的接口(getter),外部代码和类的内部细节解耦——就算类的内部逻辑改烂了,只要接口不变,外部代码就不用改。
三、getter函数的命名规范(行业通用)
为了代码可读性,getter函数有固定命名习惯:
- 普通属性:
get + 属性名(首字母大写),比如getName()、getScore(); - 布尔类型属性:
is + 属性名(比如isPass():判断是否及格,代替getPass())。
示例(布尔型getter):
class Student {
private:
int score;
public:
Student(int s) : score(s) {}
// 布尔型:is+属性(是否及格)
bool isPass() const {
return score >= 60;
}
};
int main() {
Student stu(85);
if (stu.isPass()) {
cout << "及格" << endl;
}
return 0;
}
四、补充:getter和setter是“搭档”(可选)
和getter配套的是setter函数(修改器函数),作用是“安全地修改私有属性”(比如修改分数时校验合法性):
class Student {
private:
int score;
public:
// setter:修改分数,加校验(不能是负数)
void setScore(int s) {
if (s >= 0 && s <= 100) { // 合法范围:0~100
score = s;
} else {
cout << "分数非法!" << endl;
}
}
// getter:读取分数
int getScore() const {
return score;
}
};
int main() {
Student stu;
stu.setScore(90); // 合法:score=90
stu.setScore(-50); // 非法:提示“分数非法”,score不变
cout << stu.getScore() << endl; // 输出90
return 0;
}
总结
外部可直接改属性,数据易混乱 | 外部只能通过getter读,类控制规则 |
内部改属性逻辑,外部代码全要改 | 内部改逻辑,外部调用代码不变 |
无法实现“只读属性” | 只给getter,即可实现只读 |
违背封装原则 | 符合面向对象封装思想 |
getter函数的核心:把类的内部数据“锁起来”,只留一个可控的“读取通道”,既保证数据安全,又提高代码可维护性——这是面向对象编程的基础实践,也是工业级代码的标配。
在C++中,将自定义类的多个实例存入容器(如vector/list/map等,最常用vector)是非常基础且高频的操作,核心步骤是:定义类 → 选择容器类型 → 创建类对象 → 存入容器 → 访问/遍历容器中的类对象。
下面以「包含两个属性的Student类」为例,从基础(存储对象本身) 到进阶(存储指针/智能指针) 完整讲解,所有代码可直接运行。
一、核心前置:定义包含两个属性的类
首先定义一个自定义类(比如Student),包含两个属性(如name和score),并编写构造函数(方便快速创建对象),可选写成员函数(如打印属性)。
#include <iostream>
#include <vector> // 容器头文件
#include <string> // 字符串头文件
#include <memory> // 智能指针头文件(进阶用)
using namespace std;
// 定义自定义类:包含两个属性(name/score)
class Student {
public:
// 两个核心属性(可设为public,或用get/set封装,新手先public)
string name; // 属性1:姓名
int score; // 属性2:分数
// 构造函数:快速初始化对象(必须!否则无法便捷创建实例)
Student(string n, int s) : name(n), score(s) {}
// 可选:成员函数,打印属性(方便后续遍历输出)
void showInfo() const {
cout << "姓名:" << name << ",分数:" << score << endl;
}
};
二、基础版:容器存储「类对象本身」(值语义)
最直观的方式:容器类型为vector<Student>,直接存储类的实例(对象),适合对象体积小、无需多态的场景。
实现步骤:
- 创建
vector<Student>类型的容器; - 用
emplace_back(推荐)或push_back添加类对象; - 遍历容器,访问对象的属性/调用成员函数。
完整代码:
int main() {
// 1. 创建容器:存储Student对象
vector<Student> stuContainer;
// 2. 创建多个Student对象,存入容器(两种方式,优先emplace_back)
// 方式1:emplace_back(推荐):直接在容器内存中构造对象,减少拷贝,效率更高
stuContainer.emplace_back("张三", 85); // 传入构造函数参数,直接构造
stuContainer.emplace_back("李四", 92);
// 方式2:push_back:先创建临时对象,再拷贝到容器(效率略低)
stuContainer.push_back(Student("王五", 78));
// 3. 遍历容器,访问类的属性/调用成员函数
cout << "=== 遍历容器中的Student对象 ===" << endl;
// 范围for遍历(const& 避免拷贝,只读更安全)
for (const auto& stu : stuContainer) {
// 方式1:直接访问属性(public属性可直接读)
// cout << stu.name << ":" << stu.score << endl;
// 方式2:调用成员函数(更封装)
stu.showInfo();
}
// 4. 单独访问某个对象的属性(通过下标)
cout << "\n第一个学生的分数:" << stuContainer[0].score << endl;
return 0;
}
输出结果:
=== 遍历容器中的Student对象 === 姓名:张三,分数:85 姓名:李四,分数:92 姓名:王五,分数:78 第一个学生的分数:85
三、进阶版1:容器存储「类对象指针」(指针语义)
当类对象体积大、需要避免拷贝,或需要多态(比如子类对象存入父类指针容器)时,选择存储指针:容器类型为vector<Student*>。
实现步骤:
- 创建
vector<Student*>容器; - 用
new创建类对象(堆内存),将指针存入容器; - 遍历容器,用
->访问属性/调用成员函数; - 必须手动释放内存(否则内存泄漏)。
完整代码:
int main() {
// 1. 创建容器:存储Student对象的指针
vector<Student*> stuPtrContainer;
// 2. new创建对象,指针存入容器(堆内存)
stuPtrContainer.push_back(new Student("赵六", 90));
stuPtrContainer.push_back(new Student("钱七", 88));
// 3. 遍历容器:指针用->访问成员
cout << "=== 遍历容器中的Student指针 ===" << endl;
for (auto ptr : stuPtrContainer) {
ptr->showInfo(); // 指针访问成员:->
// 也可直接访问属性:cout << ptr->name << ":" << ptr->score << endl;
}
// 4. 关键:手动释放堆内存(避免内存泄漏)
cout << "\n释放内存..." << endl;
for (auto ptr : stuPtrContainer) {
delete ptr; // 释放单个对象
}
stuPtrContainer.clear(); // 清空容器(可选)
return 0;
}
输出结果:
=== 遍历容器中的Student指针 === 姓名:赵六,分数:90 姓名:钱七,分数:88 释放内存...
四、进阶版2:容器存储「智能指针」(现代C++,推荐)
手动释放指针容易遗漏导致内存泄漏,现代C++推荐用智能指针(unique_ptr/shared_ptr),自动管理内存,无需手动delete。
核心:vector<unique_ptr<Student>>(独占指针,最常用)
unique_ptr保证每个指针唯一指向一个对象,超出作用域自动释放内存。
完整代码:
int main() {
// 1. 创建容器:存储unique_ptr<Student>(智能指针)
vector<unique_ptr<Student>> stuSmartContainer;
// 2. 用make_unique创建智能指针,存入容器(C++14及以上支持)
stuSmartContainer.push_back(make_unique<Student>("孙八", 76));
stuSmartContainer.emplace_back(make_unique<Student>("周九", 82));
// 3. 遍历容器:智能指针用->访问成员
cout << "=== 遍历容器中的智能指针 ===" << endl;
for (const auto& ptr : stuSmartContainer) {
ptr->showInfo();
}
// 4. 无需手动释放!unique_ptr自动销毁,内存自动回收
return 0;
}
输出结果:
=== 遍历容器中的智能指针 === 姓名:孙八,分数:76 姓名:周九,分数:82
五、关键注意事项(避坑!)
- 构造函数必须有:若未写构造函数,编译器会生成默认构造函数,但无法便捷初始化属性;自定义带参数的构造函数后,默认构造函数会被覆盖,需手动添加(如果需要)。
- emplace_back vs push_back:emplace_back:直接在容器内存中构造对象,无拷贝,效率更高;push_back:先创建临时对象,再拷贝/移动到容器,适合已有对象的场景; 优先用emplace_back。
- 存储对象 vs 存储指针:存储对象无需手动管理内存、简单对象拷贝开销大、不支持多态对象小、无多态需求存储裸指针无拷贝、支持多态需手动释放内存(易泄漏)对象大、需多态存储智能指针无拷贝、支持多态、自动释放C++11+支持、语法稍复杂现代开发首选(替代裸指针)
- 访问权限:若类的属性设为private(封装推荐),需编写getter函数访问属性,比如:
六、拓展:多态场景(子类对象存入父类指针容器)
如果有子类(如GraduateStudent继承Student),存储父类指针容器可实现多态:
// 父类:Student(添加虚函数支持多态)
class Student {
public:
string name;
int score;
Student(string n, int s) : name(n), score(s) {}
// 虚函数:支持多态
virtual void showInfo() const {
cout << "本科生:" << name << ",分数:" << score << endl;
}
};
// 子类:GraduateStudent
class GraduateStudent : public Student {
public:
string research; // 新增属性:研究方向
GraduateStudent(string n, int s, string r) : Student(n, s), research(r) {}
// 重写虚函数
void showInfo() const override {
cout << "研究生:" << name << ",分数:" << score << ",研究方向:" << research << endl;
}
};
int main() {
// 父类指针容器,可存子类对象(多态)
vector<unique_ptr<Student>> polyContainer;
polyContainer.push_back(make_unique<Student>("本科生张三", 85));
polyContainer.push_back(make_unique<GraduateStudent>("研究生李四", 92, "人工智能"));
// 遍历:自动调用子类重写的函数(多态)
for (const auto& ptr : polyContainer) {
ptr->showInfo();
}
return 0;
}
输出结果:
本科生:本科生张三,分数:85 研究生:研究生李四,分数:92,研究方向:人工智能
总结
核心流程:
定义类(带构造函数) → 选择容器类型(对象/指针/智能指针) → 创建类实例存入容器 → 遍历/访问类成员
- 新手优先用「存储对象 + emplace_back」,简单无内存风险;
- 进阶场景(对象大/多态)用「智能指针容器」,兼顾效率和内存安全;
- 永远避免裸指针容器的内存泄漏问题(要么手动释放,要么用智能指针)。

京公网安备 11010502036488号