注:本文以一个例子来演示广义表的基本操作,含有一个头文件《GList.h》和一个测试源文件《main.cpp》
由于问题没有具体的上下文和代码,无法确定访问冲突是指什么,因此无法给出具体的解决方案。请提供更多信息或代码以便更好的解决问题。
这种情况我也遇到过很多次,一般不是编辑器的问题而是代码的问题。但是你没有贴详细代码以及报错点所以我无法帮助你进行诊断。你可以自行检查一下是不是野指针(指针指向一个非预料的地址)等问题(指针是极危险的!),如果你用到了指针,请仔细检查调用它的函数以及它自身调用的函数(比如erase等)!
//MyString.h
#ifndef __MYSTRING_H__
#define __MYSTRING_H__
#include<iostream>
using namespace std;
class MyString
{
public:
MyString();
MyString(const char * p);
MyString(const MyString & s);
~MyString();
MyString & operator=(const MyString & s);
const char * get_string() const { return m_pbuf; } // 取得字符串的首地址
const char * set_string(const char * p = NULL); // 将 p 指向的字符串保存在MyString类中
const char * append(const char * p = NULL); // 将 p 指向的字符串追加到原有字符串之后
MyString & append(MyString & s); // 将 s 对象中的字符串追加到当前对象的字符串之后并返回对象
int get_length() const { return strlen(m_pbuf); } // 取得保存的字符串的长度
friend ostream & operator<< (ostream & o, const MyString & s); // 插入符,文本模式
void write_binary(ostream & o) const // 二进制模式输出函数
{
int len = strlen(m_pbuf); // 取得字符串占用的空间的大小,即字符串的长度
o.write((char *)&len, sizeof(int)); // 在输出流中写入字符串所占空间的大小
o.write(m_pbuf, len); // 从m_pbuf开始写入len个字节;注意:最后一个零字符未写入
}
MyString & read_binary(istream & in) // 二进制模式读取函数
{
delete[] m_pbuf; //首先回收之前的内存
int len;
in.read((char *)&len, sizeof(int)); //先读取将要读取的字符串的长度
m_pbuf = new char[len + 1]; //准备接受数据的空间:要多一个字节用于保存零字符
in.read(m_pbuf, len); //读取len个字节到m_pbuf指向的空间
m_pbuf[len] = '\0'; //在最后加上结尾符号
return *this;
}
private:
char * m_pbuf;
};
#endif
//MyString.cpp
#include "MyString.h"
ostream & operator<< (ostream & o, const MyString & s)
{
o << s.m_pbuf; return o;
}
MyString::MyString()
{
m_pbuf = new char('\0');
//cout << "MyString的默认构造函数被调用" << endl;
}
MyString::MyString(const char * p)
{
if (NULL == p)
m_pbuf = new char('\0');
else
{
int len = strlen(p) + 1;
m_pbuf = new char[len];
strcpy_s(m_pbuf, len, p);
}
//cout << "MyString的有参构造函数被调用" << endl;
}
MyString::MyString(const MyString & s)
{
int len = strlen(s.m_pbuf) + 1;
m_pbuf = new char[len];
strcpy_s(m_pbuf, len, s.m_pbuf);
//cout << "MyString的复制构造函数被调用" << endl;
}
MyString::~MyString()
{
delete [] m_pbuf;
//cout << "MyString的析构函数被调用" << endl;
}
MyString & MyString::operator=(const MyString & s)
{
if(this != &s) // 防止自赋值
{
delete [] m_pbuf;
int len = strlen(s.m_pbuf) + 1;
m_pbuf = new char[len];
strcpy_s(m_pbuf, len, s.m_pbuf);
}
//cout << "MyString的赋值运算符函数被调用" << endl;
return *this;
}
const char * MyString::set_string(const char * p)
{
delete[] m_pbuf;
if (NULL == p)
m_pbuf = new char('\0');
else
{
int len = strlen(p) + 1;
m_pbuf = new char[len];
strcpy_s(m_pbuf, len, p);
}
return m_pbuf;
}
const char * MyString::append(const char * p)
{
if (NULL != p)
{
int len = strlen(m_pbuf) + strlen(p) + 1;
char * tmp = new char[len];
sprintf_s(tmp, len, "%s%s", m_pbuf, p);
delete[] m_pbuf;
m_pbuf = tmp;
}
return m_pbuf;
}
MyString & MyString::append(MyString & s)
{
int len = strlen(m_pbuf) + s.get_length() + 1;
char * tmp = new char[len];
sprintf_s(tmp, len, "%s%s", m_pbuf, s.m_pbuf);
delete[] m_pbuf;
m_pbuf = tmp;
return *this;
}
//student.h
#pragma once
#include"MyString.h"
class CStudent
{
public:
CStudent() : number(0), score(0) { /*cout << "CStudent的默认构造函数被调用" << endl;*/ } //提供默认的构造函数,从而为new一个数组提供可能
CStudent(const int num, const MyString & name, const MyString & major, const double score);
virtual ~CStudent() { } //为方便可能的派生,定义虚析构函数
void set_number(int num) { number = num; }
int get_number() const { return number; } //该函数不改变成员的值,故设计为常成员函数
MyString & set_name(const MyString & name);
MyString & get_name() { return name; } //返回引用,从而可以对name作进一步运算
const MyString get_name() const { return name; } //常成员函数返回值对象,给常对象使用;调用该函数时会调用MyString的复制构造函数初始化返回值对象,等返回语句执行完毕,会调用析构函数析构该临时对象
MyString & set_major(const MyString & major);
MyString & get_major() { return major; }
const MyString get_major() const { return major; }
void set_score(double score) { this->score = score; }
double get_score() const { return score; }
//默认的赋值运算符
CStudent & operator=(const CStudent & stu)
{
if (this != &stu)
{
number = stu.number;
name = stu.name; //调用MyString类的赋值运算符函数
major = stu.major; //调用MyString类的赋值运算符函数
score = stu.score;
}
//cout << "CStudent的赋值运算符函数被调用" << endl;
return *this;
}
//friend ostream & operator<<(ostream & o, const CStudent & s);
//以二进制模式写文件
virtual void write_binary(ostream & out) const
{
out.write((char*)&number, sizeof(int)); //写入学号
name.write_binary(out); //写入姓名
major.write_binary(out); //写入专业
out.write((char*)&score, sizeof(double)); //写入成绩
}
//以二进制模式读文件
virtual CStudent* read_binary(istream & in)
{
in.read((char*)&number, sizeof(int)); //读取学号
name.read_binary(in); //读取名字
major.read_binary(in); //读取专业
in.read((char*)&score, sizeof(double)); //读取成绩
return this;
}
virtual void show(ostream & o) const {
o << number << "\t" << name << "\t" << major << "\t" << score;
}
private:
int number;
MyString name;
MyString major;
double score;
};
class CGraduate : public CStudent
{
public:
CGraduate() { }
CGraduate(const int number, const MyString & name,
const MyString & major, const double score, const MyString & supervisor)
: CStudent(number, name, major, score), supervisor(supervisor)
{ }
virtual ~CGraduate() { }
MyString & get_supervisor() { return supervisor; }
const MyString get_supervisor() const { return supervisor; }
//MyString & set_supervisor(const char * p) { supervisor.set_string(p); return supervisor; }
MyString & set_supervisor(const MyString & s) { supervisor = s; return supervisor; }
//friend ostream & operator<<(ostream & o, const CGraduate & s);
virtual void write_binary(ostream & out) const
{
this->CStudent::write_binary(out);
supervisor.write_binary(out);
}
virtual CStudent * read_binary(istream & in)
{
this->CStudent::read_binary(in);
supervisor.read_binary(in);
return this;
}
virtual void show(ostream & o) const {
CStudent::show(o);
o << "\t" << supervisor;
}
private:
MyString supervisor;
};
class CSinoforeign : public CStudent
{
public:
CSinoforeign() { }
CSinoforeign(const int number, const MyString & name,
const MyString & major, const double score, const double IELTSscore)
: CStudent(number, name, major, score), supervisor(supervisor)
{ }
virtual ~CSinoforeign() { }
MyString & get_supervisor() { return supervisor; }
const MyString get_supervisor() const { return supervisor; }
//MyString & set_supervisor(const char * p) { supervisor.set_string(p); return supervisor; }
MyString & set_supervisor(const MyString & s) { supervisor = s; return supervisor; }
//friend ostream & operator<<(ostream & o, const CGraduate & s);
virtual void write_binary(ostream & out) const
{
this->CStudent::write_binary(out);
supervisor.write_binary(out);
}
virtual CStudent * read_binary(istream & in)
{
this->CStudent::read_binary(in);
supervisor.read_binary(in);
return this;
}
virtual void show(ostream & o) const {
CStudent::show(o);
o << "\t" << supervisor;
}
private:
MyString supervisor;
};
//student.cpp
#include"student.h"
using namespace std;
//ostream & operator<<(ostream & o, const CStudent & s)
//{
// o << s.number << " " << s.name << " " << s.major << " " << s.score << endl;
// return o;
//}
CStudent::CStudent(const int num, const MyString & name, const MyString & major, const double score)
: number(num), name(name), major(major), score(score)
{
//cout << "CStudent的有参构造函数被调用" << endl;
}
MyString & CStudent::set_name(const MyString & name)
{
this->name = name;
return this->name;
}
MyString & CStudent::set_major(const MyString & major)
{
this->major = major;
return this->major;
}
//ostream & operator<<(ostream & o, const CGraduate & s)
//{
// o << (CStudent)s;
// o << s.get_supervisor() << endl;
// return o;
//}
//StudentList.h
#pragma once
#include"student.h"
//class CStudent;
void showError(int idx);
class CNode
{
friend class CStudentList;
friend class CAssociation;
public:
//要求p指向堆上的一个CStudent对象,且构造之后由CNode负责管理该对象
CNode(CStudent * p) : pstu(p), ref(0), next(NULL)
{
}
~CNode() { delete pstu; }
CStudent * get_student() { return pstu; }
int get_ref() const { return ref; }
void set_next(CNode * p) { next = p; }
CNode * get_next() { return next; }
private:
CNode(const CNode &); //声明为私有函数,禁止调用
CNode & operator=(const CNode &); //声明为私有函数,禁止调用
CStudent * pstu;
int ref;
CNode * next;
};
class CStudentList
{
public:
CStudentList() : head(NULL), count(0) { }
virtual ~CStudentList()
{
CNode * tmp = head.next;
while (NULL != tmp) //依次删除链表中的接点
{
head.next = tmp->next;
delete tmp;
tmp = head.next;
}
}
//添加一个学生到链头,其中p指向堆中的一个CStudent对象,且执行之后该对象由CStudentList管理
void add(CStudent * p)
{
CNode * tmp = new CNode(p);
tmp->next = head.next;
head.next = tmp;
++count;
}
//根据学号删除学生,删除成功返回0;查无此人返回1;引用数不为0不能删除返回2
int del(int num)
{
CNode * tmp = head.next, *pre = NULL;
while (NULL != tmp)
{
if (tmp->pstu->get_number() != num)
{
pre = tmp;
tmp = tmp->next;
}
else
break;
}
if (NULL == tmp) //查无此人
return 1;
else if(tmp->ref > 0) //引用数不为0,不能删除
return 2;
else
{
pre->next = tmp->next;
delete tmp;
--count;
return 0;
}
}
//通过学号取得学生所在结点的地址,如果学生不存在则返回空指针
CNode * get(int num) const
{
CNode * tmp = head.next;
while (NULL != tmp)
{
if (tmp->pstu->get_number() != num)
tmp = tmp->next;
else
break;
}
if (NULL == tmp) //查无此人
return NULL;
else
return tmp;
}
int get_count() const { return count; }
//void show() const
//{
// cout << "学号\t姓名\t专业\t\t成绩\t导师\t引用计数" << endl;
// CNode * tmp = head->next;
// while (NULL != tmp)
// {
// tmp->get_student()->display(cout);
// cout << "\t";
// if (NULL == dynamic_cast<CGraduate*>(tmp->get_student()))
// cout << "\t";
// cout << tmp->ref << endl;
// tmp = tmp->next;
// }
//}
bool clear() //清空当前对象中的数据,成功返回true,否则返回false
{
bool flag = true;
CNode * tmp = head.next;
while (NULL != tmp) //依次删除链表中的接点
{
if (0 == tmp->ref)
{
head.next = tmp->next;
delete tmp;
tmp = head.next;
--count;
}
else
{
flag = false;
break;
}
}
return flag;
}
protected:
//因使用多态,无法实现复制构造函数和赋值运算符,故将它们设为私有的
CStudentList(const CStudentList & stuMng);
CStudentList & operator=(const CStudentList & stuMng);
CNode head;
int count;
};
//可以扩展学生列表类,在其中只实现读写的功能函数。注意:该类中能够管理的学生类型是已知的
//这里只实现二进制格式的读写
class CStudentListEx : public CStudentList
{
public:
void show() //const
{
cout << "学号\t姓名\t专业\t\t成绩\t导师\t引用计数" << endl;
CNode * tmp = head.get_next();
while (NULL != tmp)
{
tmp->get_student()->show(cout);
cout << "\t";
if (NULL == dynamic_cast<CGraduate*>(tmp->get_student()))
cout << "\t";
cout << tmp->get_ref() << endl;
tmp = tmp->get_next();
}
}
void write_binary(ostream & out)
{
//取得每一个学生并逐个写入文件:本科生的标记为1,研究生的标记为2
int flag = 1;
CStudent * p = NULL;
CNode * tmp = head.get_next();
while (NULL != tmp)
{
flag = 1;
p = tmp->get_student();
if (dynamic_cast<CGraduate*>(p))
flag = 2;
out.write((char*)&flag, sizeof(int));
p->write_binary(out); //写学生信息
tmp = tmp->get_next();
}
flag = -1;
out.write((char*)&flag, sizeof(int)); //-1作为结束标记
}
bool read_binary(istream & in)
{
if (!this->clear())
return false;
int flag;
CStudent * p = NULL;
in.read((char*)&flag, sizeof(int));
while (-1 != flag)
{
if (1 == flag) //是本科生
p = new CStudent;
else
p = new CGraduate;
p->read_binary(in);
this->add(p);
in.read((char*)&flag, sizeof(int));
}
return true;
}
};
//社团类不在讲义中
class CAssociation
{
public:
CAssociation(MyString & s) : name(s), ppList(NULL), count(0) { }
~CAssociation() //由于学生与社团是聚合关系,故此处只需要回收ppList指向的空间
{
for (int i = 0; i < count; ++i) //在删除ppList之前将学生的引用计数减1
--ppList[i]->ref;
delete[] ppList;
}
int index(CNode * p) //检查p结点是否已在社团中,已在则返回其索引,否则返回-1
{
int i = 0;
for (i = 0; i < count; ++i)
if (p == ppList[i])
return i;
return -1;
}
void add(CNode * p) //添加一个学生
{
if (NULL == p || index(p) >= 0)
return;
else
{
CNode ** tmp = new CNode*[count + 1];
for (int i = 0; i < count; i++)
tmp[i] = ppList[i];
tmp[count] = p;
++tmp[count]->ref; //引用计数加1
delete[] ppList;
ppList = tmp;
++count;
}
}
//从社团中删除指向结点p的指针,成功删除返回0;如果学生不在社团则返回3
int del(CNode * p)
{
int i = index(p);
if (i < 0) //学生不在社团中
return 3;
else
{
--ppList[i]->ref; //引用计数减1
CNode ** tmp = NULL;
if(count > 1)
tmp = new CNode*[count - 1];
for (int j = 0; j < count; j++)
{
if (j == i)
continue;
if (j < i)
tmp[j] = ppList[j];
else
tmp[j - 1] = ppList[j];
}
delete[] ppList;
ppList = tmp;
--count;
return 0;
}
}
void show() const
{
cout << name.get_string() << "成员名单:" << endl;
cout << "学号\t姓名\t专业\t\t成绩\t导师\t引用计数" << endl;
for(int i = 0; i < count; ++i)
{
ppList[i]->get_student()->show(cout);
cout << "\t";
if (NULL == dynamic_cast<CGraduate*>(ppList[i]->get_student()))
cout << "\t";
cout << ppList[i]->get_ref() << endl;
}
}
void clear()
{
for (int i = 0; i < count; ++i)
--ppList[i]->ref;
delete ppList;
ppList = NULL;
count = 0;
}
void write_binary(ostream & out)
{
//只需要写入学号
int number;
for (int i = 0; i < count; ++i)
{
number = ppList[i]->get_student()->get_number();
out.write((char*)&number, sizeof(int));
}
number = -1;
out.write((char*)&number, sizeof(int)); //-1作为结束标记
//以下是一个典型的错误实现
//CStudent * p = NULL;
//CNode * tmp = ppList[0];
//while (NULL != tmp)
//{
// int num = tmp->get_student()->get_number();
// out.write((char*)&num, sizeof(int));
// tmp = tmp->get_next();
//}
}
bool read_binary(istream & in, const CStudentList & list)
{
this->clear();
int number;
in.read((char*)&number, sizeof(int));
while (-1 != number)
{
CNode * p = list.get(number);
this->add(p);
in.read((char*)&number, sizeof(int));
}
return true;
}
private:
CAssociation(const CAssociation &);
CAssociation & operator=(const CAssociation &);
MyString name;
CNode ** ppList;
int count;
};
//StudentList.cpp
#include <iostream>
#include "StudentList.h"
using namespace std;
char ErrorMsg[][100] = { "", //0-无错误
"查无此人!", //1
"被其它数据引用,不能删除!", //2
"不在社团中!" }; //3
void showError(int idx) { cout << ErrorMsg[idx] << endl; }
//main.cpp
#include<iostream>
#include<fstream>
#include"student.h"
#include"studentlist.h"
using namespace std;
int main()
{
CStudentListEx stuList;
CStudent * pstu1, * pstu2, * pstu3;
pstu1 = new CStudent(1, MyString("Liu"), MyString("security "), 100);
pstu2 = new CGraduate(2, MyString("Zhang"), MyString("security "), 90, MyString("Zhao"));
pstu3 = new CSinoforeign(3, MyString("Wang"), MyString("software engineering "), 80, 7.5);
stuList.add(pstu1);
stuList.add(pstu2);
stuList.add(pstu3);
cout << "列出所有学生" << endl;
stuList.show();
ofstream out("test.dat", ios_base::binary);
stuList.write_binary(out);
out.close();
stuList.clear();
cout << "列出所有学生" << endl;
stuList.show();
ifstream in("test.dat", ios_base::binary);
stuList.read_binary(in);
in.close();
cout << "列出所有学生" << endl;
stuList.show();
system("pause");
return 0;
}