【C++高级编程】(一)C++速成

本章内容:

  • 简要回顾C++语言最重要的部分及语法

(主要讲述日常编程会遇到的最重要的C++部分,大佬快速浏览即可)


 1.1 C++基础知识

  • C++是基于C语言的超集,但这两种语言并不一样

1.1.1 小程序的"hello world"

//HelloWorld.cpp
#include<iostream>

int main()
{
    std::cout <<  "Hello world" << std::endl;
    return 0;
}
  1. 注释
    • 第一行是注释
    • 两种写法:两条斜杠开头(C++风格)或/**/包裹(C风格)
    • 注释仅供程序员阅读,编译器自动忽略不运行
  2. 预处理指令
    • 第二行是预处理指令
    • 预处理指令以#字符开始
    • include 指令首先告诉预处理器,提取<iostream>头文件中所有内容提供给当前文件,<iostream>头文件声明了C++提供的输入输出机制(没有此头文件,将无法执行输入输出文本)
    • 在C中,被包含的文件常以 .h 结尾,C++中标准库的头文件则省略了这一后缀
    • C中的标准头文件在C++中仍然存在,但换用了新名称(如<stdio.h>变成了<cstdio>)
  3. main()函数
    • main() 函数是程序的入口
    • main() 函数返回一个 int 值以指示程序的最终状态
  4. 输入/输出流
    • 可以将输出流想象为数据的滑槽,放入其中的任何内容都可以被正确的输出
    • std::cout 就是对应于用户控制台或标准输出的滑槽,还有其他滑槽,包括用于输出错误信息的 std::cerr 
    • std::cout 输出流可以在一行代码中连续输出多个不同类型的数据(std::cout << "文本" << 123;)
    • std::cin 输入流接受用户的键盘输入,但需慎重(永远不知道用户会输入什么奇奇怪怪的东西)
    • std::endl 代表序列的结尾换行,另一种换行符是:转义字符\n
      • \n  换行
      • \r  回车
      • \t  制表符
      • \\  一个反斜杠
      • \"  一个引号

1.1.2 命名空间

using namespace std;
  1. :: 被称为作用域解析运算符
  2. 命名空间用来处理不同代码段间的名称冲突问题(如:第三方库中有Func()函数,而自己也写了Func()函数,就可以把自己写的放进 namespace mycode{ Func(){} },从而调用 mycode::Func(); )
  3. 使用 using 指令避免预先指明命名空间,使用 using namespace mycode,就可以直接调用 Func(); 
复制代码
#include<iostream>
#include"namespace.h"
namespace mycode
{
    int A = 0;
    void Func()
    {
        std::cout << "Func()" << std::endl;
    }
}

//将Func()函数放进命名空间之后,就与第三方库函数Func()区分开来,可调用:
mycode::Func();
mycode::A;
复制代码

上面代码等价于:

复制代码
#include<iostream>
#include"namespace.h"
using namespace mycode
{
    int A = 0;
    void Func()
    {
        std::cout << "Func()" << std::endl;
    }
}

//将Func()函数放进命名空间之后,就与第三方库函数Func()区分开来,可调用:
Func();
A;
复制代码

 

一个源文件中可以包含多个 using 指令,此方法虽然快捷,但不要过度使用

  1. 使用整个命名空间:using namespace [name];
  2. 使用命名空间中的变量:using [name]::[variable];
  3. 使用默认命名空间中的变量:::[variable];

 

1.1.3 变量

  1. 声明变量时,可以不指定值(未初始化的变量通常被赋予一个半随机值,bug)
  2. C++中常见变量类型:
复制代码
int a;
short b;
long c;
long long d;

// unsigned 对上面类型加以限制,使之为正数
unsigned int aa;
unsigned short bb;
unsigned long cc;
unsigned long long dd;

//浮点型(单/双精度)
float e = 3.14f;
double f;
long double g;

//字符型(单个字符,单个16位字符,单个32位字符,单个宽字符)
char h = 'm';
char16_t h1 = u'm';
char16_t h2 = U'm';
wchar_t h3 = L'm';

//布尔型,结果返回 true / false
bool i = true;

//auto 编译器自动判断类型
auto j = 10;  //应该为int型
复制代码
  • C++没有提供基本的字符串类型,但作为标准库的一部分提供了字符串的标准实现

 

3. 三种显式转换变量类型:

bool IfBool = (bool) IfInt;
bool IfBool = bool(IfInt);
bool IfBool = static_cast<bool>(IfInt);
  • 在某些环境中,可以自动执行类型转换 / 强制转换
  • 但有时,自动类型转换存在潜在的数据丢失(如:float 转换为 int 会丢失小数部分)

 

1.1.4 运算符

  • 如果记不住C++运算符的优先级,建议使用括号将表达式分组

 

1.1.5 类型

  1. 枚举类型
复制代码
enum Color{red = 2,green,blue = 5,pink}; 
//默认情况下,所枚举元素第一个名称的值为0,第二个名称的值为1,第三个名称的值为2,以此类推。(枚举值不能同名)
//但此处设置了初始化值,默认情况下,每个名称都会比它前面一个名称大1,所以:red = 2,green = 3,blue = 5,pink = 6
int main()
{
    Color a = Color::red;
    switch (a)
    {
        case red:
            cout << a << endl; //red = 2
            break;
        case green:
            cout << a << endl; //green = 3
            break;
        case blue:
            cout << a << endl; //blue = 5
            break;
        default:
            cout << a << endl; //pink = 6
            break;
    }
    return 0;
}
复制代码

 

2. 强枚举类型

上面给出的枚举并不是强类型的,这意味着其并非类型安全的,基本上会被当作整型数据 int 解释

enum class Color{red = 2,green,blue = 5,pink};
//Color 是一个类型安全的枚举,其枚举值不会自动转换为整数,枚举名称不会自动超出封闭的作用域
  • 默认情况下,枚举值的基本类型是整型

 

3. 结构

结构允许将一个或多个已有类型封装到一个新的类型中

Struct Student{
    string Name;  //学生姓名
    int age;  //学生年龄
    int score;  //学生分数
};  //分号

 

1.1.6 条件

1. if / else 语句

if(){}
else if(){}
else{}
//()圆括号内的结果必须是布尔值

 

2. switch 语句

复制代码
switch(){
    case 1:
        //执行代码
        break;
    case 2:
        //执行代码
        break;
    ....
    default:
        //执行代码
        break;
}
//如果省略 break ,将会无视case判断,直接执行后面的代码
复制代码

 

3. 三元运算符

(i = 0) ? 1 : 2;
// 判断括号内是否正确,正确返回1,错误返回2
//相当于 if(i = 0){ return 1; } else{ return 2; }

 

1.1.7 循环

1. while 循环

while(){ //执行代码; }

 

2. do / while 循环

do { //执行代码; }
while();

 

3. for 循环

for(int i=0; i; i++){ //执行代码; }

 

4. 基于区间的for循环

int arr[] = {1,2,3,4};
for(auto &i : arr){ i+=2; }

 

1.1.8 数组

  1.  声明数组时,必须用常量值来声明数组的大小
  2. 数组第一个元素的位置是0
int Array[10] = {0};
//声明一个长度为10且所有值初始化为0的数组

 

3. std::array

    • 在C++11之前, 如果想用更安全的数组类型,应该使用 std::vector(可自动扩容,当空间已满时会自动扩到原来2倍,有时造成空间浪费)
    • C++11引入了 std::array 的新型容器,该容器在 <array> 头文件中定义
    • 优点:
      • 知道自身大小(有固定大小,运行时数组不会增大缩小);
      • 不会自动转换为指针;
      • 具有迭代器,可以方便地遍历元素
      • (由于支持迭代器,STL的算法在 std::array 中也有效) 

 

复制代码
#include<iostream>
#include<array>  //头文件
using namespace std;

int main()
{
    array<int, 3>arr = { 4,5,6 };
    cout << "数组大小:" << arr.size() << endl;  //数组大小:3
    for (auto i : arr)  //遍历数组
    {
        cout << i << endl;
    }
    return 0;
}
复制代码

 

1.1.9 函数

 

  1.  如果函数在某个特定文件内部使用,通常会在源文件中声明并定义这个函数;
  2. 如果函数是供其他模块或文件使用的,通常会在头文件中声明函数,并在源文件中定义函数
//函数的声明:
void Func(int a)
{
    cout << a << endl;
}
//void 指明该函数无返回值return

 

3. C++11中,每个函数都有一个预定义的局部变量 __func__ (const char的一个静态数组),用于存放函数的名字

static const char __func__[] = "function-name";
  • 还可以将这个变量用于日志

 

1.2 深入研究C++

 1.2.1 指针及动态内存

 (动态内存允许所创建的程序具有在编译时大小可变的数据,大部分复杂的程序都会使用动态内存)

  1.  栈和堆
    •  C++程序中的内存被分为两个部分:堆、栈

 2. 动态分配的数组

    • 由于栈的运行方式,编译器在编译时必须能够判断每个栈的大小,因此栈的大小被预先确定,从而不能声明大小可变的数组(数组长度不允许使用变量:arr[n] )
    • 使用动态内存将数组放入堆,这样就可以在运行时指定数组的大小
复制代码
int ArraySize = 10;
int Array[ArraySize];
//数组放在栈中,编译器需要知道数组的确切大小,因此不允许使用变量

//1.为了动态分配数组,首先要声明一个指来指去的指针
int *p;
//int 类型后的*说明变量指向堆中某段整型内存(可将指针想象成一个箭头,它指向动态分配的堆内存,这个指针尚未指向任何具体内容,还是一个未赋值未初始化的变量)

//2.为了用新的堆内存初始化指针,使用new
p = new int [ArraySize];
//内存大小与ArraySize变量对应,指针变量仍在栈中,但动态创建的数组在堆中

//3.现在已经分配好了内存,可将Array当作普通数组使用
Array[3] = 10;

//4.假如用完了数组,一定要用delete释放空间
delete []Array;
//delete后的方括号表示删除一个数组
复制代码

 

    • 调用new就要相应的调用delete释放,以免造成内存泄漏(同理,malloc对应free)
    • 为避免常见的内存问题,应该使用智能指针。智能指针对象超出作用域时,会自动释放内存
#include<memory>  //头文件

unique_ptr<int[]>Array(new int[ArraySize]);
//unique_ptr版本可以自动释放内存

 

3. 使用指针

    • 除了动态分配内存外,还可以将任意变量放到堆中
int *a = new int;
//此时,指针指向一个整型值的地址,为了访问这个值,需要对指针解除引用

//在解除引用前,指针必须有效(对null或未初始化的指针解引用会导致程序崩溃)
int num = 10;
int *a = &num;
//为了让指针指向某个变量,需要使用&取址运算符

 

    • 指向结构的指针
    • 通常向函数传递变量是按值传递;
    • 使用指向堆栈变量的指针以允许函数修改其堆栈中的变量,是按引用传递

 

1.2.2 C++中的字符串

1. C风格字符串

    • 将字符串看成字符数组
      char ArrayString[20] = "Hello World";
      //编译器在栈中分配了20个字符的空间,以'H'开头,以'\0'结尾('\0'表示字符串的结尾),'\0'告诉代码字符串结尾的位置
      
      const char *p = "Hello World";
      //编译器在栈中分配足够的内存以存放指针p,指针指向编译器存放该常量字符串"Hello World"分配的内存区域,'d'后面也有一个'\0'字符结尾

2. C++风格字符串

    • 将字符串封装在一个易于使用的string类型中
      #include<string>
      //<string>头文件中string类型位于std命名空间中
      
      string s = "Hello World";
      //对于C风格的字符串使用==时,实际上是比较字符数组的地址,而非内容;
      //对于C++的string,==是比较两个string

       

 3. 非标准字符串

    • 开发架构及操作系统倾向于使用自己的字符串表示方式
    • 开始一个C++项目时,提前决定如何表示字符串非常重要

 

1.2.3 引用

  1.  传值,不影响变量
    void Func1(int i)
    {
        i++;
    }

     

  2. 传引用,修改了原始变量的值
    void Func(int &i)
    {
        i++;
    }

     

 1.2.4 异常

  1. C++是一种非常灵活的语言,但并不十分安全。异常就是试图增加一点安全性的语言特性 
  2. 异常是一种无法预料的情形,伴随着一些新术语,当某段代码检测到异常时,就会抛出一个异常
    • throw:当问题出现,程序抛出一个异常。抛异常使用throw关键字完成。
    • catch:用于捕捉异常。catch(...)可以捕获任意类型的异常,主要时用来捕获没有显示捕获类型的异常。相当于条件判断中的else。
    • try:try中包含会出现异常的代码或者函数。后面通常会跟一个或者多个catch块。

 

1.2.5 const 的多种用法

  1.  const 定义常量
    const int a = 10;
    //在C语言中,程序员经常使用预处理器#define机制进行声明;
    //而C++鼓励使用 const 取代 #define 定义常量

     

  2.  使用 const 保护参数
    void Func(const char* s) {}
    //调用函数Func()时,char* 会自动转换为 const char* ,提供一定程度的保护,防止其他代码修改变量

     

  3.  const 引用

const 引用其主要价值在于效率:函数传值时需要一个完整的副本;而传引用时实际只是传递了一个指向原始数据的指针(这样计算机就不需要制作副本);通过传递 const 引用,可以两者兼顾:不需要副本,原始变量也不会被修改

 

 1.3 作为面向对象语言的C++

  1.  声明类
    •  类定义了对象的特征
    • 在C++中,类通常在头文件中声明,在对应源文件中完整定义
      复制代码
      //在.h 头文件
      
      class ATest  //首先定义一个类名称ATest
      {
      public:
          //公有访问域:声明类的方法(行为)
          int getA() { return A; };
          void setA(int num) {};
      
      protected:
          //私有访问域:声明类的数据成员(属性)
          int A;
      };  //分号
      复制代码

       

 1.4 标准库

  1.  使用标准库中的类:
    • 使用标准库中的类性能更高(经过时间检验),比使用自己的类效率更高
    • 不需要重新创建某些类,也不需要浪费时间重新造轮子
    • 上面涉及的一些标准库中的类:如 std::string、std::cout 类等
    • 标准库提供的容器概念:如 std::vector
      • 以一种更灵活安全的机制取代了C中数组的概念
      • 不用担心内存的管理,vector 会自动分配足够的内存来存放元素
      • vector 是动态的,可以在运行时添加 / 删除元素
      • 为了更方便的遍历容器中的内容,标准库还提供了迭代器的概念
        复制代码
        #include<iostream>
        #include<vector>  //头文件
        #include<string>
        using namespace std;
        
        int main()
        {
            //A 被声明为vector<string>,尖括号内用来指定模板参数
            //vector 是一个泛型容器,几乎可以容纳任何类型的对象
            vector<string> A = {"Hello World","Hello My World"};
        
            //为了向 vector 中添加元素,调用 push_back() 方法
            A.push_back("Hi");
        
            //使用 auto 关键字让编译器自动判断变量B的类型
            for (auto B = A.cbegin(); B != A.cend(); ++B)
            {
                cout << *B << endl;
            }
        
            for(auto & str:A)
            {
                cout << str << endl;
            }
        
            return 0;
        }
        复制代码

         

 1.5 一个C++程序案例

  1.  此案例属上文知识的汇总,使用了上面讲到的类、异常、流、向量、迭代器、命名空间、引用及其他语言特性
  2. 建立一个雇员数据库,包含以下功能:
    • 添加雇员
    • 删除雇员
    • 雇员晋升
    • 查看所有雇员(以前和现在的雇员)
    • 查看当前雇员
    • 查看以前雇员
  3.  程序分为三大部分:
    • Employee 类(封装单个雇员信息)
    • DataBase 类(管理公司所有雇员)
    • 单独的一份 UserInterface 文件提供程序接口

 

1.5.1 Employee 类

Employee 类用于维护某个雇员的全部信息

  1. Employee.h
    复制代码
    // Employee.h文件:声明了Employee类的行为
    
    #include<string>
    namespace Records 
    { 
        //新雇员的默认起薪,存于Records命名空间中;
        //Records中其他代码可以通过常量kDefaultStartingSalary访问,
        //而其他位置需通过Records::kDefaultStartingSalary来引用
        const int kDefaultStartingSalary = 30000; 
    
        //声明Employee类
        class Employee
        {
        public:  //公有方法
            Employee();  //构造函数
            void promote(int inRaiseAmount = 1000);
            void demote(int inDemeritAmount = 1000);
            void hire();
            void fire();
            void displayer()const;
    
            void setFirstName(std::string inFirstName);
            std::string getFirstName()const;
            void setLastName(std::string inLastName);
            std::string getLastName()const;
            void setEmployeeNumer(int inEmployeeNumber);
            int getEmployeeNumer()const;
            void setSalary(int inNewSalary);
            int getSalary()const;
            bool getInHired()const;
    
        protected:  //私有数据成员
            std::string mFirstName;
            std::string mLastName;
            int mEmployeeNumber;
            int mSalary;
            bool bHired;
        };
    }
    复制代码

     

  2. Employee.cpp
    复制代码
    // Employee.cpp文件:Employee类方法的实现
    
    #include<iostream>
    #include"Employee.h"
    using namespace std;
    namespace Records 
    {
        //构造函数初始化数据成员:新雇员无名,雇员号-1,薪水为默认值,状态为未雇佣
        void Employee::Employee() 
        {
            mFirstName="";
            mLastName="";
            mEmployeeNumber = -1;
            mSalary = kDefaultStartingSalary;
            bHired = false;
        }
    
        //promote()和demote()方法只是简单调用setSalary()方法
        void Employee::promote(int inRaiseAmount)
        {
            setSalary(getSalary() + inRaiseAmount);
        }
        void Employee::demote(int inDemeritAmount)
        {
            setSalary(getSalary() - inDemeritAmount);
        }
    
        //hire()和fire()方法设置了bHired数据成员
        void Employee::hire()
        {
            bHired = true;
        }
        void Employee::fire()
        {
            bHired = false;
        }
    
        //displayer()方法使用控制台输出流显示当前雇员信息
        //可以直接访问内部数据成员,而不需要使用get存取器
        void Employee::displayer() const
        {
            cout << "Employee:" << getFirstName() << ", " << getLastName() << endl;
            cout << "------------------------------------------------------" << endl;
            cout << (bHired ? "Current Employee" : "Former Employee") << endl;
            cout << "Employee Number: " << getEmployeeNumer() << endl;
            cout << "Salary: $" << getSalary() << endl;
            cout << endl;
        }
    
        //使用存取器get和设置器set,而不建议将数据成员公开
        void Employee::setFirstName(string inFirstName)
        {
            mFirstName = inFirstName;
        }
        string Employee::getFirstName() const
        {
            return mFirstName;
        }
    }
    复制代码

     

  3. EmployeeTest.cpp
    复制代码
    // EmployeeTest.cpp文件:Employee类方法的实现
    
    #include<iostream>
    #include"Employee.h"
    using namespace std;
    using namespace Records;
    
    int main()
    {
        Employee emp;
        emp.setFirstName("Ann");
        emp.setLastName("Tom");
        emp.setEmployeeNumer(888);
        emp.setSalary(100000);
        emp.promote();
        emp.promote(50);
        emp.hire();
        emp.displayer();
    
        return 0;
    }
    复制代码

     

1.5.2 DataBase 类

DataBase 类使用了标准库中的 std::vector 类存储 Employee 对象

  1. DataBase.h
    复制代码
    // DataBase.h文件:DataBase类方法的实现
    
    #include<iostream>
    #include<vector>
    #include"Employee.h"
    namespace Records
    {
        //雇员编号初始化
        const int kFirstEmployeeNumber = 1000;
    
        class DataBase
        {
        public:
            DataBase();
            ~DataBase();
    
            //通过姓名添加雇员
            Employee& addEmployee(std::string inFirstName, std::string inLastName);
    
            //get的两个版本:可以通过雇员号检索,或雇员姓名检索
            Employee& getEmployee(int inEmployeeNumber);
            Employee& getEmployee(std::string inFirstName, std::string inLastName);
    
            //输出所有雇员,在职雇员,离职雇员
            void displayAll() const;
            void displayCurrent() const;
            void displayFormer() const;
    
        protected:
    
            //mEmployees包含了Employee对象
            std::vector<Employee> mEmployees;
    
            //数据成员mNextEmployeeNumber跟踪新雇员的雇员号
            int mNextEmployeeNumber;
        };
    }
    复制代码

     

  2. DataBase.cpp
    复制代码
    // DataBase.cpp文件:数据库管理
    
    #include<iostream>
    #include<stdexcept>
    #include"DataBase.h"
    using namespace std;
    namespace Records
    {
        //构造函数将下一雇员号初始化
        DataBase::DataBase()
        {
            mNextEmployeeNumber = kFirstEmployeeNumber;
        }
        DataBase::~DataBase()
        {
        }
    
        //添加雇员
        Employee& DataBase::addEmployee(std::string inFirstName, std::string inLastName)
        {
            //首先创建一个新Employee对象,并填充数据
            //mNextEmployeeNumber的值递增,下一雇员将获得新的编号
            Employee theEmployee;
            theEmployee.setFirstName(inFirstName);
            theEmployee.setLastName(inLastName);
            theEmployee.setEmployeeNumer(mNextEmployeeNumber++);
            theEmployee.hire();
            mEmployees.push_back(theEmployee);
            
            // TODO: 在此处插入 return 语句
            return mEmployees[mEmployees.size() - 1];
        }
    
        //两个getEmployee()的运行方式相似
        Employee& DataBase::getEmployee(int inEmployeeNumber)
        {
            //使用迭代器遍历mEmployees中的所有雇员
            //(如果编译器不支持auto,可使用vector<Employee>::iterator 替换)
            for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter)
            {
                //检查是否有与传递该方法的信息匹配的员工
                if (iter->getEmployeeNumer() == inEmployeeNumber) { return *iter; }
            }
            
            //没有则输出错误信息,并抛出异常
            cerr << "No Employee with number" << inEmployeeNumber << endl;
            throw exception();
        }
    
        //显示的方法同理,遍历所有雇员,如果符合显示标准就通知雇员显示自己
        void DataBase::displayAll() const
        {
            //(如果编译器不支持auto,可使用vector<Employee>::const_iterator 替换,因为是const成员函数)
            for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter)
            {
                iter->displayer();
            }
        }
        void DataBase::displayCurrent() const
        {
            for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter)
            {
                if (iter->getInHired()) { iter->displayer(); }
            }
        }
    }
    复制代码

     

  3. DataBaseTest.cpp
    复制代码
    // DataBaseTest.cpp文件:数据库基本功能的简单测试实现
    
    #include<iostream>
    #include"DataBase.h"
    using namespace std;
    using namespace Records;
    
    int main()
    {
        DataBase DB;
        Employee& emp1 = DB.addEmployee("Greg", "Wallis");
        emp1.fire();
        Employee& emp2 = DB.addEmployee("Scott", "Klep");
        emp2.setSalary(20000);
        Employee& emp3 = DB.addEmployee("Nick", "Solter");
        emp3.setSalary(120000);
        emp3.promote();
    
        cout << "All Employee:" << endl << endl;
        DB.displayAll();
        cout << "Current Employee:" << endl << endl;
        DB.displayCurrent();
        cout << "Former Employee:" << endl << endl;
        DB.displayFormer();
    
        return 0;
    }
    复制代码

     

1.5.3 用户界面

  1. UserInterface.cpp
    复制代码
    // UserInterface.cpp文件:基于菜单的用户界面,方便用户使用雇员数据库
    
    #include<iostream>
    #include<stdexcept>
    #include"DataBase.h"
    using namespace std;
    using namespace Records;
    int displayMenu();
    void doHire(DataBase& inDB);
    void doFire(DataBase& inDB);
    void doPromote(DataBase& inDB);
    void doDemote(DataBase& inDB);
    
    //输出菜单,并获取用户输入(在此假定用户能正常输入)
    int displayMenu()
    {
        int selection;
        cout << endl
             << "Employee DataBase" << endl
             << "--------------------------------------" << endl;
    
        cout << "1)Hire a new employee" << endl
             << "2)Fire an employee" << endl
             << "3)Promote an employee" << endl
             << "4)List all employees" << endl
             << "5)List all current employees" << endl
             << "6)List all previous employees" << endl
             << "0)Quit" << endl << endl
             << "--------------------------------------" << endl;
    
        cin >> selection;
        return selection;
    }
    
    //获取用户输入的新雇员名字,并通知数据库添加雇员
    void doHire(DataBase& inDB)
    {
        string firstName;
        string lastName;
    
        cout << "FirstName?" << endl;
        cin >> firstName;
        cout << "LastName?" << endl;
        cin >> lastName;
    
        //遇到错误时,会输出一条信息并继续
        try{
            inDB.addEmployee(firstName, lastName);
        }
        catch (const std::exception&) {
            cerr << "Unable to add new employee!" << endl;
        }
    }
    
    //doFire()和doPromote()都会根据雇员号找到雇员数据,然后使用Employee的方法进行修改
    void doFire(DataBase& inDB)
    {
        int employeeNumber;
    
        cout << "Employee Number?" << endl;
        cin >> employeeNumber;
        try {
            Employee& emp = inDB.getEmployee(employeeNumber);
            emp.fire();
            cout << "Employee:" << employeeNumber << "terminated." << endl;
        }
        catch(const std::exception&){
            cerr << "Unable to terminate employee!" << endl;
        }
    }
    
    void doPromote(DataBase& inDB)
    {
        int employeeNumber;
        int raiseAmount;
    
        cout << "Employee Number?" << endl;
        cin >> employeeNumber;
        cout << "How much of a raise?" << endl;
        cin >> raiseAmount;
    
        try {
            Employee& emp = inDB.getEmployee(employeeNumber);
            emp.promote(raiseAmount);
        }
        catch (const std::exception) {
            cerr << "Unable to promote employee!" << endl;
        }
    }
    
    //main函数是一个显示菜单的循环
    int main()
    {
        DataBase employeeDB;
        bool done = false;
        while (!done)
        {
            int selection = displayMenu();
            switch (selection)
            {
            case 1:
                doHire(employeeDB);
                break;
            case 2:
                doFire(employeeDB);
                break;
            case 3:
                doPromote(employeeDB);
                break;
            case 4:
                employeeDB.displayAll();
                break;
            case 5:
                employeeDB.displayCurrent();
                break;
            case 6:
                employeeDB.displayFormer();
                break;
            case 0:
                done = true;
                break;
            default:
                cout << "Unkonwn." << endl;
            }
        }
        return 0;
    }
    复制代码

     

如果不理解上面程序,建议回顾前面的内容;如果仍不甚明了,最好的学习方法是多写多敲

 -END-

posted @   哟吼--小文文公主  阅读(847)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示