C++文件读写,从外部的文件读取数据, 学生和teacher的数据没有读出来

问题遇到的现象和发生背景

现将 Person Student Teacher Grades 数据封装 然后外部文件读取进行测试

问题相关代码,请勿粘贴截图

Grades.h

#pragma once
#include<iostream>
#include"Student.h"
#include"Teacher.h"
#include"Student.h"
#include <map>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <windows.h>
#include <io.h>
using namespace std;
class CGrades
{
private:
    string ID;//班级编号
    string grade;//级
    string special;//专业
    
    istringstream iss;//文件流
    string lineStr;//文件中的一行数据
    string fileName; //全路径文件名
public:
    CStudent stu[50];//班级中的50个学生
    CTeacher teacher[5];//班级中的5个老师
    CGrades();//无参构造
    CGrades(string _id, string _grade, string _special, CStudent _stu[], CTeacher _tea[]);//有参构造
    CGrades(const CGrades&obj);//拷贝构造
    //virtual ~CGrades();

    //修改数据
    void SetID(string _id);//编号
    void SetGrades(string _grade);//级
    void Setspecial(string _special);//专业

    string Getspecial(void);//得到专业
    float classavergpa();//班级平均绩点
    void graphicsort();//图形图像的成绩排序
    void SetStudent(CStudent _stu, int _index);//
    float GetAverageGPA(int _index);//计算第_index的平均绩点

    CStudent ReturnStudent(int m);
    CTeacher ReturnTeacher(int m);

    void printCGradesInfo();//输出CGrades内各个数据值
    void ReadFileToCStudent(std::string _fileName);//从文件中读取数据到CStudent
    void ReadFileToCTeacher(std::string _fileName);//从文件中读取数据到CTeacher
    //void ReadFileToCGrades(std::string _fileName);//从文件中读取数据到CGrades
};


Person.h

#pragma once
#include<iostream>

using namespace std;
class CPerson
{
private:
    string name;//姓名
    float age;//年龄
    string gender;//性别
    string address;//出生地
    string nationality;//国籍
public:
    CPerson();//无参构造
    CPerson(string _na, float _age, string _gender, string _address, string _nation);//有参构造
    CPerson(const CPerson& obj);//拷贝构造

    //修改数据
    void SetName(string _na);//姓名
    void SetAge(float _age);//年龄
    void SetGender(string _gender);//性别
    void SetAddress(string _address);//出生地
    void SetNationality(string _nation);//国籍

    //
    string GetName(void);//得到姓名
    string GetAddress(void);//得到出生地
    float GetAge(void);//得到年龄
    //
    void printPersonInfo();//输出CPerson内各个数据值

};



Student.h

#pragma once
#include<iostream>
#include"Person.h"
#include<vector>
using namespace std;
class CStudent :public CPerson//继承CPerson
{
private:
    string ID;//学号
    string special;//专业
    float cProgram;//C语言成绩
    float oop;//面向对象成绩
    float os;//操作系统成绩
    float graphic;//图形图像成绩
    float machineLearning;//机器学习成绩
public:
    CStudent();//无参构造
    CStudent(string _id, string _special, float _c, float _oop, float _os, float _graphic, float _ml);//有参构造
    CStudent(const CStudent &obj);//拷贝构造
    //virtual ~CStudent();

    //修改数据
    void SetID(string _id);//学号
    void SetSpecial(string _special);//专业
    void SetCProgram(float _c);//C语言成绩
    void SetOOP(float _oop);//面向对象成绩
    void SetOS(float _os);//操作系统成绩
    void SetGraphic(float _graphic);//图形图像成绩
    void SetMachineLearning(float _ml);//机器学习成绩
    //
    string GetID(void);//得到学号
    float GetCProgram(void);//得到C语言成绩
    float GetOOP(void);//得到面向对象成绩
    float Getos(void);//得到操作系统的成绩
    float GetGraphic(void);//得到图形图像成绩
    float GetMachineLearning(void);//得到机器学习的成绩
    float oopGPA(float _oop);//计算面向对象成绩绩点
    float GetAverageGPA(void);//计算平均绩点
    float sum();//计算总成绩
    void Set(const CStudent &obj);//
    void printCStudentInfo();//输出CStudent内各个数据值
    //
    //std::vector<CStudent> ReadFileToCStudent(std::string _fileName);//从文件中读取数据到CStudent
};




Teacher.h

#pragma once
#include<iostream>
#include"Person.h"
#include<vector>
using namespace std;
class CTeacher :public CPerson//继承CPerson
{
private:
    string ID;//工号
    string special;//岗位
    float salary;//薪资
    string title;//职称
    string education;//学历
public:
    CTeacher();//无参构造
    CTeacher(string _id, string _special, float _salary, string _title, string _edu);//有参构造
    CTeacher(const CTeacher&obj);//拷贝构造
    //virtual ~CTeacher();

    //修改数据
    void SetID(string _id);//工号
    void SetSpecial(string _special);//岗位
    void SetSalary(float _salary);//薪资
    void SetTitle(string _title);//职称
    void SetEducation(string _edu);//学历

    //
    float GetSalary();//得到年收入
    float yearsalary(void);//计算老师年收入

    //
    void printCTeacherInfo();//输出CTeacher内各个数据值
    //std::vector<CTeacher> ReadFileToCTeacher(std::string _fileName);//从文件中读取数据到CTeacher
};


Grades.cpp

#include "Grades.h"
#include<string>
#include"Student.h"
#include"Person.h"
CGrades::CGrades()//无参构造
{
    ID = "";//班级编号
    grade = "";//级
    special = "";//专业
}
CGrades::CGrades(string _id, string _grade, string _special, CStudent _stu[], CTeacher _tea[])//有参构造
{
    ID = _id;//班级编号
    grade = _grade;//级
    special = _special;//专业
}
CGrades::CGrades(const CGrades&obj)//拷贝构造
{
    ID = obj.ID;//班级编号
    grade = obj.grade;//级
    special = obj.special;//专业
    for (int i = 0; i < 50; i++)
    {
        stu[i] = obj.stu[i];
    }
    for (int i = 0; i < 10; i++)
    {
        teacher[i] = obj.teacher[i];
    }
}
//CGrades:: ~CGrades()
//{
//
//}

//修改数据
void CGrades::SetID(string _id)//编号
{
    ID = _id;
}
void CGrades::SetGrades(string _grade)//级
{
    grade = _grade;
}
void CGrades::Setspecial(string _special)//专业
{
    special = _special;
}
//
string CGrades::Getspecial(void)//得到专业
{
    return special;
}
float CGrades::classavergpa()//班级平均绩点
{
    float gpa = 0.0;
    for (int i = 0; i < 50; i++)
    {
        gpa = gpa + stu[i].GetAverageGPA() / 50;
    }
    return gpa;
}
void CGrades::graphicsort()//图形图像的成绩排序
{
    CStudent _stu;
    int i, j;
    for (i = 0; i < 50; i++)
    {
        for (j = 1; j < 49; j++)
        {
            if (stu[i].GetGraphic() < stu[j].GetGraphic())
            {
                _stu = stu[i];
                stu[i] = stu[j];
                stu[j] = _stu;
            }
        }
    }
    //输出排序信息
    for (i = 0; i < 50; i++)
    {
        stu[i].printCStudentInfo();
    }
}
void CGrades::SetStudent(CStudent _stu, int _index)
{
    stu[_index].Set(_stu);

}
float CGrades::GetAverageGPA(int _index)//计算第_index的平均绩点
{
    return stu[_index].GetAverageGPA();
}
//
void CGrades::printCGradesInfo()//输出CGrades内各个数据值
{
    for (int i = 0; i < 50; i++)
    {
        cout << "第 " << i << "学生信息如下:" << endl << endl;
        stu[i].printCStudentInfo();
    }
    for (int i = 0; i < 5; i++)
    {
        cout << "第 " << i << "老师信息如下:" << endl << endl;
        teacher[i].printCTeacherInfo();
    }
}

CStudent CGrades::ReturnStudent(int m)//用于返回得到student的信息
{
    return stu[m];
}
CTeacher CGrades::ReturnTeacher(int m)//用于返回得到teacher的信息
{
    return teacher[m];
}

void CGrades::ReadFileToCStudent(std::string _fileName)//从文件中读取数据到CStudent
{
    fileName = _fileName;
    //std::vector<double> dataVec;
    //按行读取,每行的结束是回车区分
    std::ifstream ifs(_fileName);
    int lineIndex = 0;//计数行数
    if (ifs)
    {
        while (getline(ifs, lineStr))//获取文件中的每一行数据
        {
            iss.clear();
            iss.str(lineStr); //把字符串lineStr复制给iss
            string str1;
            double str2;
            int i = 0;


            while (iss >> str1)
            {
                if (i == 0)
                {
                    stu[lineIndex].SetID(str1);

                }
                else if (i == 1)
                {
                    stu[lineIndex].SetSpecial(str1);
                    break;
                }

                i++;
            }
            i = 2;
            while (iss >> str2)
            {
                if (i == 2)
                {
                    stu[lineIndex].SetCProgram(str2);

                }
                else if (i == 3)
                {
                    stu[lineIndex].SetOOP(str2);

                }
                else if (i == 4)
                {
                    stu[lineIndex].SetOS(str2);

                }
                else if (i == 5)
                {
                    stu[lineIndex].SetGraphic(str2);
                }
                else if (i == 6)
                {
                    stu[lineIndex].SetMachineLearning(str2);

                }
                else
                    break;
                i++;
            }
            lineIndex++;
        }
    }
    
}

void CGrades::ReadFileToCTeacher(std::string _fileName)//从文件中读取数据到CTeacher
{
    fileName = _fileName;
    //std::vector<double> dataVec;
    //按行读取,每行的结束是回车区分
    std::ifstream ifs(_fileName);
    int lineIndex = 0;//计数行数
    if (ifs)
    {
        while (getline(ifs, lineStr))//获取文件中的每一行数据
        {
            iss.clear();
            iss.str(lineStr); //把字符串lineStr复制给iss
            string str1;
            double str2;
            int i = 0;


            while (iss >> str1)
            {
                if (i == 0)
                {
                    teacher[lineIndex].SetID(str1);

                }
                else if (i == 1)
                {
                    teacher[lineIndex].SetSpecial(str1);
                    iss >> str2;
                    teacher[lineIndex].SetSalary(str2);
                    i++;
                }
                else if (i == 3)
                {
                    teacher[lineIndex].SetTitle(str1);

                }
                else if (i == 4)
                {
                    teacher[lineIndex].SetEducation(str1);

                }
                else if (i == 2)
                {
                }
                else
                    break;
                i++;
            }
            lineIndex++;
        }
    }

}



Person.cpp

#include "Person.h"
#include<string>
CPerson::CPerson()//无参构造
{
    name = "";//姓名
    age = 0;//年龄
    gender = "";//性别
    address = "";//出生地
    nationality = "";//国籍
}
CPerson::CPerson(string _na, float _age, string _gender, string _address, string _nation)//有参构造
{
    name = _na;//姓名
    age = _age;//年龄
    gender = _gender;//性别
    address = _address;//出生地
    nationality = _nation;//国籍
}
CPerson::CPerson(const CPerson& obj)//拷贝构造
{
    name = obj.name;//姓名
    age = obj.age;//年龄
    gender = obj.gender;//性别
    address = obj.address;//出生地
    nationality = obj.nationality;//国籍
}

//修改数据
void CPerson::SetName(string _na)//姓名
{
    name = _na;
}
void CPerson::SetAge(float _age)//年龄
{
    age = _age;
}
void CPerson::SetGender(string _gender)//性别
{
    gender = _gender;
}
void CPerson::SetAddress(string _address)//出生地
{
    address = _address;
}
void CPerson::SetNationality(string _nation)//国籍
{
    nationality = _nation;
}

//
string CPerson::GetName(void)//得到姓名
{
    return name;
}
string CPerson::GetAddress(void)//得到出生地
{
    return address;
}
float CPerson::GetAge(void)//得到年龄
{
    return age;
}
//
void CPerson::printPersonInfo()//输出CPerson内各个数据值
{
    cout << "姓名: " << name << endl;//姓名
    cout << "年龄: " << age << endl;//年龄
    cout << "性别: " << gender << endl;//性别
    cout << "出生地: " << address << endl;//出生地
    cout << "国籍: " << nationality << endl;//国籍
}


Student.cpp

#include "Student.h"
#include<string>
CStudent::CStudent()//无参构造
{
    ID = "";//学号
    special = "";//专业
    cProgram = 0;//C语言成绩
    oop = 0;//面向对象成绩
    os = 0;//操作系统成绩
    graphic = 0;//图形图像成绩
    machineLearning = 0;//机器学习成绩
}
CStudent::CStudent(string _id, string _special, float _c, float _oop, float _os, float _graphic, float _ml)//有参构造
{
    ID = _id;//学号
    special = _special;//专业
    cProgram = _c;//C语言成绩
    oop = _oop;//面向对象成绩
    os = _os;//操作系统成绩
    graphic = _graphic;//图形图像成绩
    machineLearning = _ml;//机器学习成绩

}
CStudent::CStudent(const CStudent &obj)//拷贝构造
{
    ID = obj.ID;//学号
    special = obj.special;//专业
    cProgram = obj.cProgram;//C语言成绩
    oop = obj.oop;//面向对象成绩
    os = obj.os;//操作系统成绩
    graphic = obj.graphic;//图形图像成绩
    machineLearning = obj.machineLearning;//机器学习成绩
}
//CStudent:: ~CStudent()
//{
//
//}

//修改数据

//
string CStudent::GetID(void)//得到学号
{
    return ID;
}
float CStudent::GetCProgram(void)//得到C语言成绩
{
    return cProgram;
}
float CStudent::GetOOP(void)//得到面向对象成绩
{
    return oop;
}
float CStudent::Getos(void)//得到操作系统的成绩
{
    return os;
}
float CStudent::GetGraphic(void)//得到图形图像成绩
{
    return graphic;
}
float CStudent::GetMachineLearning(void)//得到机器学习的成绩
{
    return machineLearning;
}
void CStudent::SetID(string _id)//学号
{
    ID = _id;
}
void CStudent::SetSpecial(string _special)//专业
{
    special = _special;
}
void CStudent::SetCProgram(float _c)//C语言成绩
{
    cProgram = _c;
}
void CStudent::SetOOP(float _oop)//面向对象成绩
{
    oop = _oop;
}
void CStudent::SetOS(float _os)//操作系统成绩
{
    os = _os;
}
void CStudent::SetGraphic(float _graphic)//图形图像成绩
{
    graphic = _graphic;
}
void CStudent::SetMachineLearning(float _ml)//机器学习成绩
{
    machineLearning = _ml;
}
float CStudent::oopGPA(float _oop)//计算面向对象成绩绩点
{
    float oop=0.0;
    float oopgpa=0.0;//面向对象成绩绩点
    if (60 <= oop <= 100)
    {
        oopgpa = (((oop - 60) / 10) + 1);
    }
    if (0 <= oop < 60)
    {
        oopgpa = 0;
    }
    return oopgpa;
}
float CStudent::GetAverageGPA()//计算平均绩点
{
    float cgpa;//C语言成绩绩点
    float oopgpa;//面向对象成绩绩点
    float gpa = 0.0;//平均绩点
    if (60 <= cProgram <= 100)
    {
        cgpa = (((oop - 60) / 10) + 1);
    }
    if (0 <= cProgram < 60)
    {
        cgpa = 0;
    }
    float osgpa;//操作系统成绩绩点
    if (60 <= os <= 100)
    {
        osgpa = (((oop - 60) / 10) + 1);
    }
    if (0 <= os < 60)
    {
        osgpa = 0;
    }
    float graphicgpa;//图形图像成绩绩点
    if (60 <= graphic <= 100)
    {
        graphicgpa = (((oop - 60) / 10) + 1);
    }
    if (0 <= graphic < 60)
    {
        graphicgpa = 0;
    }
    float mlgpa;//机器学习成绩绩点
    if (60 <= machineLearning <= 100)
    {
        mlgpa = (((oop - 60) / 10) + 1);
    }
    if (0 <= machineLearning < 60)
    {
        mlgpa = 0;
    }
    gpa = (cgpa + oopGPA(oop) + osgpa + graphicgpa + mlgpa) / 5;
    return gpa;
}
float CStudent::sum()//计算总成绩
{
    float cProgram=0.0;//C语言成绩
    float oop=0.0;//面向对象成绩
    float os=0.0;//操作系统成绩
    float graphic=0.0;//图形图像成绩
    float machineLearning=0.0;//机器学习成绩
    return (cProgram + oop + os + graphic + machineLearning);
}
void CStudent::Set(const CStudent &obj)
{
    ID = obj.ID;//学号
    special = obj.special;//专业
    cProgram = obj.cProgram;//C语言成绩
    oop = obj.oop;//面向对象成绩
    os = obj.os;//操作系统成绩
    graphic = obj.graphic;//图形图像成绩
    machineLearning = obj.machineLearning;//机器学习成绩
}
void CStudent::printCStudentInfo()//输出CStudent内各个数据值
{
    cout << "学号: " << ID << endl;//学号
    cout << "专业: " << special << endl;//专业
    cout << "C语言成绩: " << cProgram << endl;//C语言成绩
    cout << "面向对象成绩: " << oop << endl;//面向对象成绩
    cout << "操作系统成绩: " << os << endl;//操作系统成绩
    cout << "图形图像成绩: " << graphic << endl;//图形图像成绩
    cout << "机器学习成绩: " << machineLearning << endl;//机器学习成绩
}




Teacher.cpp

#include"Teacher.h"
CTeacher::CTeacher()//无参
{
    ID = "";
    special = "";
    salary = 0;
    title = "";
    education = "";
}
CTeacher::CTeacher(const CTeacher&xx)//拷贝
{
    ID = xx.ID;
    special = xx.special;
    salary = xx.salary;
    title = xx.title;
    education = xx.education;
}
CTeacher::CTeacher(string ID1, string special1, float salary1, string title1, string education1)//有参
{
    ID = ID1;
    special = special1;
    salary = salary1;
    title = title1;
    education = education1;
}
string CTeacher::getID()//得到数据-工号
{
    return ID;
}
string CTeacher::getspecial()//得到数据-岗位
{
    return special;
}
float CTeacher::getsalary()//得到数据-薪资
{
    return salary;
}
string CTeacher::gettitle()//得到数据-职称
{
    return title;
}
string CTeacher::geteducation()//得到数据-学历
{
    return education;
}

void CTeacher::SetID(string _ID)
{
    ID = _ID;
}
void CTeacher::Setspecial(string _special) {
    special = _special;
}
void CTeacher::Setsalary(float _salary) {
    salary = _salary;
}
void CTeacher::Settitle(string _title) {
    title = _title;
}
void CTeacher::Seteducation(string _education) {
    education = _education;
}

void CTeacher::printteacher()//输出老师的信息
{
    printperson();
    cout << "工号: " << ID << endl;
    cout << "岗位: " << special << endl;
    cout << "薪资: " << salary << endl;
    cout << "职称: " << title << endl;
    cout << "学历: " << education << endl;
    cout << endl;
}


test.cpp

#include<iostream>
#include<fstream>
#include<string>
#include"Person.h"
#include"Student.h"
#include"Teacher.h"
#include"Grades.h"
using namespace std;


int main()
{

    CGrades stu;
    CGrades tea;

    cout << "输入学生的信息" << endl;
    cout << "班级学生的信息(包括学生所有信息)" << endl;
    stu.ReadFileToCStudent("C:\\Users\L.M.Y\source\repos\class.1\stuInforall.txt");
    stu.stu[0].printCStudentInfo();
    
    stu.ReturnStudent(0).printCStudentInfo();//因为person自动的初始化会把stu包含的person信息初始化消除
    cout << "老师信息" << endl;
    stu.ReadFileToCTeacher("C:\\Users\L.M.Y\source\repos\class.1\teacher.txt");//读取到stu的teacher中
    stu.ReturnTeacher(0).printCTeacherInfo();
    //stu.printCTeacherInfo();
    cout << "以上学生和老师信息的综合" << endl;
    stu.printCGradesInfo();

    cout << "班级学生信息(学号和成绩)" << endl;
    tea.ReadFileToCStudent("C:\\Users\L.M.Y\source\repos\class.1\student_txt2.txt"); //读取到stu的student中
    tea.stu[0].printCStudentInfo();
    tea.printCGradesInfo();
    /*stu.SetStudent
    for (;;)
    {
        int choice = 0;
        cout << "选择要执行的操作:" << endl;
        cout << "1:输出师生基本资料" << endl;
        cout << "2:输出学生详细资料" << endl;
        cout << "3:输出教师详细资料" << endl;
        cout << "4:输出班级详细资料" << endl;
        cin >> choice;

        if (choice == 1)
        {
            per.printPersonInfo();
        }
        if (choice == 2)
        {
            stu.printCStudentInfo();
        }
        if (choice == 3)
        {
            tea.printCTeacherInfo();
        }
        if (choice == 4)
        {
            gra.printCGradesInfo();
        }
    }*/
}
运行结果及报错内容

img

img

期待结果:
能够每个读入正确并输出

乍看起来c++的cin、cout、ifstream、ofstream、istringstream、ostringstream在输入、输出上比c的scanf、printf、fscanf、fprintf、fread、fwrite、sscanf、sprintf简单,不用格式控制符!
但是不用格式控制符,输入输出恰好是你期望的格式的时候好说;等到输入输出不是你期望的格式的时候,你就会觉得还是用格式控制符更方便、更靠谱。
摒弃cin、cout、ifstream、ofstream、istringstream、ostringstream!
使用scanf、printf、fscanf、fprintf、fread、fwrite、sscanf、sprintf。
仅供参考:

//NAME: essaie bla bla
//DIMENSION: 8
//DATA
//1  14  15
//2  11  10
//3  6   4
//4  7   13
//5  9   21
//6  19  3
//7  1   5
//8  8   8
//EOF
//
// 文本文件中可能还含有其他内容,但是需要用到的内容即以上

//比如data.txt:
//NAME: essaie bla bla
//其它内容
//DIMENSION: 8
//其它内容
//DATA
//其它内容
//1  14  15
//其它内容
//2  11  10
//其它内容
//3  6   4
//其它内容
//4  7   13
//其它内容
//5  9   21
//其它内容
//6  19  3
//其它内容
//7  1   5
//其它内容
//8  8   8
//其它内容
//EOF

// 目标是要获取NAME后字串,DIMENSION后数值,以及DATA以下的数值
// 其中NAME就是随便个字句,DIMENSION是城市数量,DATA以下是城市编号,X坐标,Y坐标
// 所有的这些将赋值给一个事先定义好的结构
#include <stdio.h>
#include <string.h>
#define MAXCPL   80   //每行最大字符数
#define MAXCITY  100  //每组数据中DATA最多项数,DIMENSION的最大值
#define MAXNAMEL 32   //NAME最大长度
struct S {
    char NAME[MAXNAMEL+1];
    int  DIMENSION;
    struct D {
        int NO;
        int X;
        int Y;
    } DATA[MAXCITY];
} s;
FILE *f;
int st,n,i;
char ln[MAXCPL];
int main() {
    f=fopen("data.txt","r");
    if (NULL==f) {
        printf("Can not open file data.txt!\n");
        return 1;
    }
    st=0;
    n=0;
    while (1) {
        if (NULL==fgets(ln,MAXCPL,f)) break;
        if (st==0) {
            if (1==sscanf(ln,"NAME: %31[^\n]",s.NAME)) st=1;
        } else if (st==1) {
            if (1==sscanf(ln,"DIMENSION: %d",&s.DIMENSION)) st=2;
        } else if (st==2) {
            if (0==strcmp(ln,"DATA\n")) st=3;
        } else if (st==3) {
            if (3==sscanf(ln,"%d%d%d",&s.DATA[n].NO,&s.DATA[n].X,&s.DATA[n].Y)) {
                n++;
                if (n>=MAXCITY || n>=s.DIMENSION) break;
            }
        }
    }
    fclose(f);
    printf("s.NAME=[%s]\n",s.NAME);
    printf("s.DIMENSION=%d\n",s.DIMENSION);
    for (i=0;i<n;i++) {
        printf("s.DATA[%d].NO,X,Y=%d,%d,%d\n",i,s.DATA[i].NO,s.DATA[i].X,s.DATA[i].Y);
    }
    return 0;
}
//s.NAME=[essaie bla bla]
//s.DIMENSION=8
//s.DATA[0].NO,X,Y=1,14,15
//s.DATA[1].NO,X,Y=2,11,10
//s.DATA[2].NO,X,Y=3,6,4
//s.DATA[3].NO,X,Y=4,7,13
//s.DATA[4].NO,X,Y=5,9,21
//s.DATA[5].NO,X,Y=6,19,3
//s.DATA[6].NO,X,Y=7,1,5
//s.DATA[7].NO,X,Y=8,8,8