• C++ 学习笔记、01 | 开发简单职工管理系统遇到的一些问题


    记录开发简单职工管理系统遇到的一些问题,黑马教程
    https://www.bilibili.com/video/BV1et411b73Z P147 ~ P166

    头文件与源文件

    • 头文件只声明,源文件来实现(本质上是类内声明类外实现)
    • 源文件需要引用特定的头文件
    ifndef OOPFINAL_WORKER_H
    #define OOPFINAL_WORKER_H
    
    #include 
    #include 
    
    using namespace std;
    
    class Worker {
    public:
        virtual void ShowInfo() = 0;
    
        virtual string getDeptName() = 0;
    
        int m_Id;
        string m_Name;
        int m_DeptId;
    };
    
    #endif //OOPFINAL_WORKER_H
    
    #ifndef OOPFINAL_MANAGER_H
    #define OOPFINAL_MANAGER_H
    
    #include 
    #include "Worker.h"
    
    using namespace std;
    
    class Manager : public Worker {
    public:
        Manager(int id, string name, int dId);
    
        void ShowInfo() override;
    
        string getDeptName() override;
    };
    
    #endif //OOPFINAL_MANAGER_H
    
    #include "../headers/Manager.h"
    
    void Manager::ShowInfo() {
        cout << "职工编号 " << m_Id << "\t职工姓名 "
             << m_Name << "\t岗位 " << getDeptName() << "\t岗位职责:完成老板交给的任务,并下发任务给普通员工" << endl;
    }
    
    string Manager::getDeptName() {
        return "经理";
    }
    
    Manager::Manager(int id, string name, int dId) {
        this->m_Id = id;
        this->m_Name = name;
        this->m_DeptId = dId;
    }
    
    

    头文件重复引用

    #ifndef,#define,#endif

    #ifndef 的方式依赖于宏名字不能冲突(最好采用这种方式

    • 保证同一个文件只会被编译一次
    • 内容完全相同的两个文件只会编译其中一个一次

    #pragma once

    同一个文件不会被编译多次(物理上的同一个文件,不是指内容相同的两个文件)


    要求整数却输入字符

    这种情况下会标志位 failbit 被置 1,字符一直在缓冲区中,没被读出,可能出现死循环

    • cin.restate() 当cin.rdstate()返回 0 (即ios::goodbit)时表示无错误,可以继续输入或者操作,若返回4则发生非致命错误即ios::failbit,则不能继续输入或操作

    • cin.fail() 可以判断流操作是否失败,输入错误后,cin.fail()返回为真 错误流标志位被置failbit为true, 当恢复时 failbit被设置为false

    • cin.clear() (默认为0 ,即无错误)清除错误的标志位

      clear有多种状态

      • goodbit 无错误
      • Eofbit 已到达文件尾
      • failbit 非致命的输入/输出错误,可挽回
      • badbit 致命的输入/输出错误,无法挽回 若在输入输出类里.需要加ios::标识符号
      • 通过设置cin.clear() 或 cin.clear(istream::goodbit)清除错误状态
    • cin.ignore() 清除缓冲区

    如果输入错误,通过cin.clear()清除了错误状态标志后,下一次cin输入时,仍会从缓冲区中读取数据,而之前的错误输入此时仍存在缓冲区中,所以还会再次被读取造成错误,所以要清空缓冲区

    • cin.ignore(要清除的字节长度,标识)

    cin.ignore(1024,’\n’)
    该函数就是将选中的字节取出抛弃掉(cin操作时是以char为单位的)
    标识清除的最大长度是1024个字节。
    清除时如果遇到‘\n’就停止,不管是否是1024个字节。
    如果没有遇到‘\n’就只清除1024个
    cin.ignore()的默认参数为cin.ignore(1,EOF),及清除文件描述符前一个字节

    cout << "输入选择" << endl;
    while (cin >> choice, cin.fail()) {
        cout << "输入有误,请重新输入" << endl;
        cin.clear();  // 清除错误标志位
        cin.ignore(); // 清除缓冲区
    }
    

    Delete[]

    在09讲,添加职工函数中,老师释放了数组空间,但没释放数组元素的空间,为什么?

    • 依旧需要原来的数组元素,在释放数组前执行了原有元素地址的拷贝
    • 新数组 = 旧数组元素 + 新添加的数组元素

    以下旨在探究 Delete 数组,会不会调用数组元素的析构器

    答案是不会,需要自己手动调用

    #include 
    
    using namespace std;
    
    class Father {
    public:
        Father() = default;
    
        virtual ~Father() {
            cout << "父元素析构器" << endl;
        };
    
    };
    
    class Son1 : public Father {
    public:
        ~Son1() {
            cout << "一号子类析构器" << endl;
        }
    };
    
    class Son2 : public Father {
    public:
        ~Son2() {
            cout << "二号子类析构器" << endl;
        }
    };
    
    
    int main() {
        Father **array = new Father *[10];
        array[0] = new Son1();
        array[1] = new Son2();
        array[2] = new Son2();
    //    delete array[0];
    //    delete array[1];
    //    delete array[2];
        delete[] array;
    
        cout << "---------" << endl;
        Father *test = new Son1();
        delete test;
        return 0;
    }
    

    文件存在且数据为空

    • 判断文件是否被打开
    • 读入一个字符,判断字符是不是文件尾部标志

    ifs.eof() 判断是要在读取到文件结束符之后才会置为true,意思也就是说即使打开一个空文件,你不读取里面的数据,ifs.eof() 会默认置为false

    peek() 尝试读取第一个字符,但不提取(光标位不后移)

    //  char ch;
    //  ifs >> ch;
        ifs.peek();
    if (ifs.eof()) {
        // 文件为空
        cout << "文件为空" << endl;
        m_EmpArray = NULL;
        m_EmpNum = 0;
        this->m_FileIsEmpty = true;
        ifs.close();
        return;
    }
    

    ifstream 回到文件头

    使用 ifstream 进行文本文件读取时,如果读指针位于文件末尾,无法直接通过调用seekg(0, ios::beg) 回到文件开头,而是需要先调用 clear() 清除指针状态,再调用seekg(0, ios::beg) 才能成功返回文件头

    • ios::beg 默认的,从流的开头开始定位
    • ios::cur 从流的当前位置开始定位
    • ios::end 从流的末尾开始定位

    override

    override明确地表示一个函数是对基类中一个虚函数的重载。更重要的是,它会检查基类虚函数和派生类中重载函数的签名不匹配问题。如果签名不匹配,编译器会发出错误信息。


    =default

    =default 是C++11引入的一种特性,它允许显式要求编译器生成默认的特殊成员函数。特殊成员函数包括默认构造函数、复制构造函数、移动构造函数、复制赋值运算符、移动赋值运算符以及析构函数


    参考资料

    cplusplus.com/reference/istream/istream/seekg/

    Set Position with seekg() in C++ File Handling - GeeksforGeeks

    cin输入的类型不匹配造成的死循环CSDN博客

    C++-关键字:override(重写)

    【#ifndef, #define, 和 #endif】

    c++新特性:=default - 知乎 (zhihu.com)


    __EOF__

  • 本文作者: 小能喵喵喵
  • 本文链接: https://www.cnblogs.com/linxiaoxu/p/17707351.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    秒杀系统设计
    Android数据存储及Room数据库的使用和原理分析
    如何根据镜像反向生成Dockerfile内容?这三种方式总有一个适合你
    List集合
    商场百货数字化会员系统引流方式 购物中心线上会员拉新
    漫画 | 重磅!七国集团决定制裁Go语言!
    vue elementui 搜索栏子组件封装
    数据结构与算法之美读书笔记11
    给Android第三方SDK传入代理Context
    LeetCode刷题笔记【24】:贪心算法专题-2(买卖股票的最佳时机II、跳跃游戏、跳跃游戏II)
  • 原文地址:https://www.cnblogs.com/linxiaoxu/p/17707351.html