1 项目内容及要求
本项目通过设计一个抽象向量类模板,以及一个通用的向量类模板和一个字符串类作为其派生类,以满足各种应用场景中的数据存储和处理需求。
项目内容:
- 抽象向量类模板。
- 派生向量类。
- 派生字符串类。
- 测试及异常处理。
- 联合测试
2.1 抽象向量类模板
2.1.1 数据成员设计
int num;//向量的维度
T* p;//存储元素的数组
2.1.2 成员函数设计
VECTOR(int size = 0, const T* x = NULL)//构造函数
VECTOR(const VECTOR& v)//拷贝构造函数
virtual ~VECTOR()//虚析构函数
VECTOR& operator=(const VECTOR& v)//赋值运算符重载
T& operator[](int index)//用于访问特定位置的元素
void resize(int size)//重设容器大小
virtual void Output(ostream& out) const = 0;//纯虚函数
virtual void Input(istream& in) = 0;//纯虚函数
2.2 派生向量类模板
2.2.1 定义纯虚函数
void Output(ostream& out) const
{
if (__super::num == 0) out << "( )";
else
{
out << "(" << __super::p[0];
for (int i = 1; i < __super::num; i++)
{
out << "," << __super::p[i];
}
out << ")" << endl;
}
}
void Input(istream& in)
{
char c;
T x;
__super::resize(0);
in >> c;
if (c != '(') return;
while (in >> x)
{
__super::resize(__super::num + 1);
__super::p[__super::num - 1] = x;
in >> c;
if (c == ')') break;
}
}
2.2.2 成员函数设计
Vector(int size = 0, const T* x = NULL)//构造函数
Vector operator+(const Vector& v)//+运算符重载
2.2.3 测试及异常处理
int TestVector()
{
int a[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
double x[8];
for (int i = 0; i < 8; i++)
x[i] = sqrt(double(i));
Vector<int> vi1(10, a), vi2(5, a + 5);
Vector<double> vd1(8, x), vd2(3, x);
cout << "原始数据:" << endl;
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "调整维数到5:" << endl;
vi1.resize(5);
vi2.resize(5);
vd1.resize(5);
vd2.resize(5);
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "\n将数据写入文件 vector.txt 中..." << endl;
ofstream outfile("vector.txt");
outfile << vi1 << '\n'
<< vi2
<< vd1 << '\n' << vd2 << endl;
outfile.close();
cout << "\n清除对象的数据(即调整维数到0)..." << endl;
vi1.resize(0);
vi2.resize(0);
vd1.resize(0);
vd2.resize(0);
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "\n从文件 vector.txt 中读取的数据:" << endl;
ifstream infile("vector.txt");
infile >> vi1 >> vi2 >> vd1 >> vd2;
infile.close();
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "\nvi1 + vi2 = " << vi1 + vi2
<< "\nvd1 + vd2 = " << vd1 + vd2 << endl;
cout << "\n异常处理测试" << endl;
Vector<int> v;
cout << "请输入一个整数向量。如 (1, 3, 5, 7)" << endl;
try
{
cin >> v;//如果格式错误,则抛出异常
}
catch (const char* str)
{
cout << str << endl;
return 0;
}
return 0;
}
运行结果:
2.3 派生字符串类
2.3.1 定义纯虚函数
void Output(ostream& out) const
{
for (int i = 0; i < __super::num; i++)
{
out << p[i];
}
}
void Input(istream& in)
{
string temp;
in >> temp;
*this = temp.c_str();
}
2.3.2 成员函数设计
String(const char* x = "")//构造函数
String operator+(const String& s)//+运算符重载
2.3.3 测试及异常处理
int TestString()
{
String str1 = "Hello", str2 = str1, str3;
// 转换构造 拷贝构造 默认构造
cout << "原始数据(双引号是另外添加的):" << endl;
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
str3 = str2; // 赋值运算
str1 = "C++ program.";
str2 = str3 + ", world!"; // 拼接运算
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
cout << "\n将数据写入文件 string.txt 中..." << endl;
ofstream outfile("string.txt");
outfile << str1 << '\n'
<< str2 << '\n'
<< str3 << endl;
outfile.close();
cout << "\n清除对象的数据(即调整长度到0)..." << endl;
str1.resize(0);
str2.resize(0);
str3.resize(0);
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
cout << "\n从文件 string.txt 中读取的数据:" << endl;
ifstream infile("string.txt");
infile >> str1
>> str2
>> str3;
infile.close();
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
cout << "\n异常处理测试" << endl;
String str4 = "Hello";
try
{
cout << str4 << endl;
cout << str4[10] << endl;//越界访问,抛出异常
}
catch (const char* str)
{
cout << str << endl;
return 0;
}
return 0;
}
运行结果:
3 联合测试
#include "Vec.h"
int TestVector(), TestString(), Test();
void menu()
{
cout << "\n1 --- testing Vector [v]"
<< "\n2 --- testing String [s]"
<< "\n3 --- testing Vector & String [m]"
<< "\n0 --- exit [q]"
<< endl;
}
int main()
{
char choice = '0';
do
{
menu();
cin >> choice;
switch (choice)
{
case '1':
case 'v':
case 'V': TestVector(); break;
case '2':
case 's':
case 'S': TestString(); break;
case '3':
case 'm':
case 'M': Test(); break;
case '0':
case 'q':
case 'Q':
case 27: choice = 0; break;
default: cout << "选择错误,重新选择" << endl; break;
}
} while (choice);
return 0;
}
int Test()
{
Vector<int> v;
String str;
cout << "请输入一个整数向量。如 (1, 3, 5, 7)" << endl;
try
{
cin >> v;
}
catch (const char* str)
{
cout << str << endl;
return 0;
}
cout << v << endl;
cin.sync(); // 刷新输入流缓冲区(目的是读取并丢弃向量后的换行符)
cout << "请输入一个字符串。如 abc 12345 xyz" << endl;
cin >> str;
cout << str << endl;
cout << "\n将数据写入文件 output.txt 中..." << endl;
ofstream outfile("output.txt");
outfile << v << endl
<< str << endl;
outfile.close();
cout << "\n清除对象的数据..." << endl;
v.resize(0);
str.resize(0);
cout << "向量:" << v << endl
<< "字符串:\"" << str << "\"" << endl;
cout << "\n从文件 output.txt 中读取的数据:" << endl;
ifstream infile("output.txt");
infile >> v;
infile >> str;
infile.close();
cout << "向量:" << v << endl
<< "字符串:\"" << str << "\"" << endl;
return 0;
}
运行结果:
4 完整代码
4.1 Vec.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
template <typename T> class VECTOR
{
public:
VECTOR(int size = 0, const T* x = NULL)
{
num = (size > 0) ? size : 0;
p = NULL;
if (num > 0)
{
p = new T[num];
for (int i = 0; i < num; i++)
p[i] = (x == NULL) ? 0 : x[i];
}
}
VECTOR(const VECTOR& v)
{
num = v.num;
p = NULL;
if (num > 0)
{
p = new T[num];
for (int i = 0; i < num; i++)
p[i] = v.p[i];
}
}
virtual ~VECTOR()
{
if (p != NULL) delete[] p;
}
VECTOR& operator=(const VECTOR& v)
{
if (num != v.num)
{
if (p != NULL) delete[] p;
p = new T[num = v.num];
}
for (int i = 0; i < num; i++)
p[i] = v.p[i];
return *this;
}
T& operator[](int index)
{
if (index >= num) throw "越界访问";
else return p[index];
}
void resize(int size)
{
if (size < 0 || size == num) return;
else if (size == 0)
{
if (p != NULL) delete[] p;
num = 0;
p = NULL;
}
else
{
T* temp = p;
p = new T[size];
for (int i = 0; i < size; i++)
p[i] = (i < num) ? temp[i] : 0;
num = size;
delete[] temp;
}
}
virtual void Output(ostream& out) const = 0;
virtual void Input(istream& in) = 0;
int num;//向量的维度
T* p;//存储元素的数组
};
template <typename T> ostream& operator<<(ostream& out, const VECTOR<T>& v)
{
v.Output(out);
return out;
}
template <typename T> istream& operator>>(istream& in, VECTOR<T>& v)
{
v.Input(in);
return in;
}
template <typename T> class Vector :public VECTOR<T>
{
public:
Vector(int size = 0, const T* x = NULL) :VECTOR<T>(size, x) {}
void Output(ostream& out) const
{
if (__super::num == 0) out << "( )";
else
{
out << "(" << __super::p[0];
for (int i = 1; i < __super::num; i++)
{
out << "," << __super::p[i];
}
out << ")" << endl;
}
}
void Input(istream& in)
{
char c;
T x;
__super::resize(0);
in >> c;
if (c != '(') throw "格式错误";
while (in >> x)
{
__super::resize(__super::num + 1);
__super::p[__super::num - 1] = x;
in >> c;
if (c == ')') break;
}
}
Vector operator+(const Vector& v)
{
Vector Add;
if (__super::num == v.__super::num)
{
Add.resize(__super::num);
for (int i = 0; i < __super::num; i++)
{
Add[i] = __super::p[i] + v.__super::p[i];
}
}
return Add;
}
};
class String : public VECTOR<char>
{
public:
String(const char* x = "")
: VECTOR<char>(strlen(x), x) { }
void Output(ostream& out) const
{
for (int i = 0; i < __super::num; i++)
{
out << p[i];
}
}
void Input(istream& in)
{
string temp;
in >> temp;
*this = temp.c_str();
}
String operator+(const String& s)
{
int i, j;
String add;
add.__super::num = __super::num + s.__super::num;
add.p = new char[add.__super::num];
for (i = 0; i < __super::num; i++)
{
add.p[i] = p[i];
}
for (j = 0; j < s.__super::num; j++)
{
add.p[i + j] = s.p[j];
}
return add;
}
};
4.2 Test.cpp
#include "Vec.h"
int TestVector(), TestString(), Test();
void menu()
{
cout << "\n1 --- testing Vector [v]"
<< "\n2 --- testing String [s]"
<< "\n3 --- testing Vector & String [m]"
<< "\n0 --- exit [q]"
<< endl;
}
int main()
{
char choice = '0';
do
{
menu();
cin >> choice;
switch (choice)
{
case '1':
case 'v':
case 'V': TestVector(); break;
case '2':
case 's':
case 'S': TestString(); break;
case '3':
case 'm':
case 'M': Test(); break;
case '0':
case 'q':
case 'Q':
case 27: choice = 0; break;
default: cout << "选择错误,重新选择" << endl; break;
}
} while (choice);
return 0;
}
int Test()
{
Vector<int> v;
String str;
cout << "请输入一个整数向量。如 (1, 3, 5, 7)" << endl;
try
{
cin >> v;
}
catch (const char* str)
{
cout << str << endl;
return 0;
}
cout << v << endl;
cin.sync(); // 刷新输入流缓冲区(目的是读取并丢弃向量后的换行符)
cout << "请输入一个字符串。如 abc 12345 xyz" << endl;
cin >> str;
cout << str << endl;
cout << "\n将数据写入文件 output.txt 中..." << endl;
ofstream outfile("output.txt");
outfile << v << endl
<< str << endl;
outfile.close();
cout << "\n清除对象的数据..." << endl;
v.resize(0);
str.resize(0);
cout << "向量:" << v << endl
<< "字符串:\"" << str << "\"" << endl;
cout << "\n从文件 output.txt 中读取的数据:" << endl;
ifstream infile("output.txt");
infile >> v;
infile >> str;
infile.close();
cout << "向量:" << v << endl
<< "字符串:\"" << str << "\"" << endl;
return 0;
}
4.3 TestString.cpp
#include "Vec.h"
int TestString()
{
String str1 = "Hello", str2 = str1, str3;
// 转换构造 拷贝构造 默认构造
cout << "原始数据(双引号是另外添加的):" << endl;
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
str3 = str2; // 赋值运算
str1 = "C++ program.";
str2 = str3 + ", world!"; // 拼接运算
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
cout << "\n将数据写入文件 string.txt 中..." << endl;
ofstream outfile("string.txt");
outfile << str1 << '\n'
<< str2 << '\n'
<< str3 << endl;
outfile.close();
cout << "\n清除对象的数据(即调整长度到0)..." << endl;
str1.resize(0);
str2.resize(0);
str3.resize(0);
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
cout << "\n从文件 string.txt 中读取的数据:" << endl;
ifstream infile("string.txt");
infile >> str1
>> str2
>> str3;
infile.close();
cout << "str1 = \"" << str1
<< "\"\nstr2 = \"" << str2
<< "\"\nstr3 = \"" << str3 << "\"" << endl;
cout << "\n异常处理测试" << endl;
String str4 = "Hello";
try
{
cout << str4 << endl;
cout << str4[10] << endl;//越界访问,抛出异常
}
catch (const char* str)
{
cout << str << endl;
return 0;
}
return 0;
}
4.4 TestVector.cpp
#include "Vec.h"
int TestVector()
{
int a[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
double x[8];
for (int i = 0; i < 8; i++)
x[i] = sqrt(double(i));
Vector<int> vi1(10, a), vi2(5, a + 5);
Vector<double> vd1(8, x), vd2(3, x);
cout << "原始数据:" << endl;
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "调整维数到5:" << endl;
vi1.resize(5);
vi2.resize(5);
vd1.resize(5);
vd2.resize(5);
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "\n将数据写入文件 vector.txt 中..." << endl;
ofstream outfile("vector.txt");
outfile << vi1 << '\n'
<< vi2
<< vd1 << '\n' << vd2 << endl;
outfile.close();
cout << "\n清除对象的数据(即调整维数到0)..." << endl;
vi1.resize(0);
vi2.resize(0);
vd1.resize(0);
vd2.resize(0);
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "\n从文件 vector.txt 中读取的数据:" << endl;
ifstream infile("vector.txt");
infile >> vi1 >> vi2 >> vd1 >> vd2;
infile.close();
cout << "vi1 = " << vi1 << "\nvi2 = " << vi2
<< "\nvd1 = " << vd1 << "\nvd2 = " << vd2 << endl;
cout << "\nvi1 + vi2 = " << vi1 + vi2
<< "\nvd1 + vd2 = " << vd1 + vd2 << endl;
cout << "\n异常处理测试" << endl;
Vector<int> v;
cout << "请输入一个整数向量。如 (1, 3, 5, 7)" << endl;
try
{
cin >> v;//如果格式错误,则抛出异常
}
catch (const char* str)
{
cout << str << endl;
return 0;
}
return 0;
}
注意:
包含项目的文件夹中以下三个文本文档需要自行创建: