面向对象程序设计|类模板

目录

题目一:简单类模板(类模板)

题目二:矩阵类模板(类模板)

题目三:有界数组模板类(类模板)

题目四:OOP 多重收纳(类模板)


题目一:简单类模板(类模板)

题目描述:

定义一个列表类,该列表包含属性:数值列表(用长度为100的数组表示),数据长度(实际的数据个数);包含的方法:初始化、插入、删除、打印,方法定义为:

1)初始化,接受外来参数,把数据保存在数值列表中,未使用的列表部分全部初始化为-1

2)插入,接受外来参数的插入位置和插入数值,插入位置从0开始计算,注意从插入位置开始,原有数据都要往后移动一位,且数据长度+1

3)删除,接受外来参数的删除位置,删除位置从0开始计算,注意从删除位置后一位开始,原有数据都要往前移动一位,且数据长度-1

4)打印,把包含的数据按位置顺序输出一行,数据之间单个空格隔开

使用类模板的方法,使得这个类支持整数int类型和浮点数double类型

输入要求:

第一行先输入参数n表示有n个数据,接着输入n个整数

第二行输入两个参数,表示插入位置和插入数值,数值为整数

第三行输入删除位置

第四行先输入参数n表示有n个数据,接着输入n个浮点数

第五行输入两个参数,表示插入位置和插入数值,数值为浮点数

第六行输入删除位置

输出要求:

针对头三行输入,分别执行初始化、插入操作和删除操作,调用打印方法输出列表包含的整数数据

针对接着的三行输入,分别执行初始化、插入操作和删除操作,调用打印方法输出列表包含的浮点数数据

输入样例:

5 11 22 33 44 55
2 888
4
5 1.1 2.2 3.3 4.4 5.5
2 88.8
3

输出样例:

11 22 888 33 55
1.1 2.2 88.8 4.4 5.5

代码示例:

#include<iostream>
#include<iomanip>
#include<cstring>
#include<string> 
#include<cmath>
#include<algorithm>
using namespace std;

template<class T>//类模板
class List
{
private:
    T number[100];
    int num;
public:
    List(int n)
    {
        for (int i = 0; i < n; i++)
        {
            cin >> number[i];
        }
        for (int i = n; i < 100; i++)
        {
            number[i] = -1;
        }
        num = n;
    }
    void insertList(int pos)
    {
        T dig;
        cin >> dig;
        for (int i = num; i > pos; i--)
        {
            number[i] = number[i - 1];
        }
        number[pos] = dig;
        num++;
    }
    void deleteList(int pos)
    {
        for (int i = pos; i < num - 1; i++)
        {
            number[i] = number[i + 1];
        }
        number[num - 1] = -1;
        num--;
    }
    void Print()
    {
        for (int i = 0; i < num; i++)
        {
            cout << number[i];
            if (i != num - 1)
            {
                cout << " ";
            }
            else
            {
                cout << endl;
            }
        }
    }
};
int main()
{
    int n;
    int pos1, pos2;
    cin >> n;
    List<int> L1(n);;//;数据是int型
    cin >> pos1;
    L1.insertList(pos1);
    cin >> pos2;
    L1.deleteList(pos2);
    L1.Print();

    cin >> n;
    List<double> L2(n);//函数数据是
    cin >> pos1;
    L2.insertList(pos1);
    cin >> pos2;
    L2.deleteList(pos2);
    L2.Print();
    return 0;
}

类模板,故名思及就是模板,记住格式!

题目二:矩阵类模板(类模板)

题目描述:

设计一个矩阵类模板Matrix,支持任意数据类型的数据。

要求至少包含2个成员函数:矩阵转置函数transport、以及打印输出函数print

编写main函数进行测试,调用类的成员函数完成转置和输出。

输入要求:

第一行先输入t,表示有t个测试用例

从第二行开始输入每个测试用例的数据。

首先输入数据类型,I表示int,D表示double,C表示char,接着输入两个参数m和n,分别表示矩阵的行和列

接下来输入矩阵的元素,一共m行,每行n个数据

输出要求:

输出转置后的矩阵

输入样例:

2
I 2 3
1 2 3
4 5 6
C 3 3
a b c
d e f
g h i

输出样例:

1 4
2 5
3 6
a d g
b e h
c f i

代码示例:

#include<iostream>
#include<iomanip>
#include<cstring>
#include<string> 
#include<cmath>
#include<algorithm>
using namespace std;

template<class T>//类模板
class Matrix
{
private:
    T** arr;
    int row, col;
public:
    Matrix(int rr, int cc) :row(rr), col(cc)
    {
        arr = new T * [row];
        for (int i = 0; i < row; i++)
        {
            arr[i] = new T[col];
        }
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                cin >> arr[i][j];
            }
        }
    }
    ~Matrix()
    {
        delete arr;
    }
    void Transport()//矩阵转置
    {
        T** temp;
        temp = new T * [col];
        for (int i = 0; i < col; i++)
        {
            temp[i] = new T[row];
        }
        for (int i = 0; i < col; i++)
        {
            for (int j = 0; j < row; j++)
            {
                temp[i][j] = arr[j][i];
            }
        }
        swap(row, col);
        arr = new T * [row];
        for (int i = 0; i < row; i++)
        {
            arr[i] = new T[col];
        }
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                arr[i][j] = temp[i][j];
            }
        }
    }
    void Print()
    {
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                cout << arr[i][j];
                if (j != col - 1)
                {
                    cout << " ";
                }
                else
                {
                    cout << endl;
                }
            }
        }
    }
};


int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        char type;
        int rval, cval;
        cin >> type >> rval >> cval;
        if (type == 'I')
        {
            Matrix<int> m1(rval, cval);//int类型矩阵
            m1.Transport();
            m1.Print();
        }
        else if (type == 'D')
        {
            Matrix<double> m2(rval, cval);//double类型矩阵
            m2.Transport();
            m2.Print();
        }
        else if (type == 'C')
        {
            Matrix<char> m3(rval, cval);//char类型矩阵
            m3.Transport();
            m3.Print();
        }
    }
    return 0;
}

题目三:有界数组模板类(类模板)

题目描述:

编写有界数组模板BoundArray(即检查对数组元素下标引用并在下标越界时终止程序的执行),能够存储各种类型的数据。要求实现对数组进行排序的方法sort,及对数组进行查找的方法search。(不能直接调用C++自带的排序或查找函数)

输入要求:

第一行先输入t,表示有t个测试用例

从第二行开始输入每个测试用例的数据。

首先输入数据类型,I表示int,D表示double,C表示char,接着输入数组的元素个数

然后输入每个元素

最后输入要查找的元素

输出要求:

首先输出从小到大排序的元素

然后输出查找元素的结果,找到则输出下标,没找到则输出-1

输入样例:

2
I 2
1 2
2
D 3
3.5 6.2 2.9
2.1

输出样例:

1 2 
1
2.9 3.5 6.2 
-1

代码示例:

#include<iostream>
#include<iomanip>
#include<cstring>
#include<string> 
#include<cmath>
#include<algorithm>
using namespace std;

template<class T>//特定格式 template<class T>
class BoundArray
{
private:
    T* arr;
    int num;
public:
    BoundArray(int nn) :num(nn)
    {
        arr = new T[num];
        for (int i = 0; i < num; i++)
        {
            cin >> arr[i];
        }
    }
    ~BoundArray()
    {
        delete arr;
    }
    void Sort()
    {
        for (int i = 0; i < num - 1; i++)
        {
            for (int j = 0; j < num - i - 1; j++)
            {
                if (arr[j] > arr[j + 1])
                {
                    swap(arr[j], arr[j + 1]);
                }
            }
        }
        for (int i = 0; i < num; i++)
        {
            cout << arr[i] << " ";
        }
        cout << endl;
    }
    void Search()
    {
        T target;
        cin >> target;
        bool mark = true;
        for (int i = 0; i < num; i++)
        {
            if (arr[i] == target)
            {
                cout << i;
                mark = false;
                break;
            }
        }
        if (mark)
        {
            cout << -1;
        }
        cout << endl;
    }
};


int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        char type;
        int n;
        cin >> type >> n;
        if (type == 'I')
        {
            BoundArray<int> ba1(n);
            ba1.Sort();
            ba1.Search();
        }
        else if (type == 'D')
        {
            BoundArray<double> ba2(n);
            ba2.Sort();
            ba2.Search();
        }
        else if (type == 'C')
        {
            BoundArray<char> ba3(n);
            ba3.Sort();
            ba3.Search();
        }
    }
    return 0;
}

题目四:OOP 多重收纳(类模板)

题目描述:

现在我们要制作一种盒子,它能够收纳多种类型的元素,比如int、double、char、string等等。

我们每接收到一个数据都将它用这种盒子包装起来,然后放到同一个vector中。

为了能够包装不同类型的元素,我们决定用模板类来实现这种盒子,并起名为CBox.

然而,我们注意到CBox<int>、CBox<char>等类虽然定义自相同的模板类,但实际上它们是不相容的类型。

为了能够放到一个vector中,我们决定为CBox模板类定义一个抽象父类CBoxObject。

这样我们就能利用父类指针将不同的CBox实例类对象集中放到一个vector<CBoxObject*>中啦。

下面给出CBoxObject抽象类的定义:(不可修改)

class CBoxObject {

protected:

    string type; // 记录类型信息

public:

    CBoxObject(string _type) : type(_type) {}

    virtual void show(ostream&) const = 0; // 用于输出信息

};

为了查看vector中任意盒子的数据,我们决定采用多态的技术来实现:

1. 要求CBox模板类继承CBoxObject类,并且要定义一个成员变量;

2. CBox要实现父类虚函数void show(ostream&),show函数将信息输出到ostream中,

   1) 一般输出格式为:{type: value}

   2) 如果元素为空指针,则输出为:{}

3. 为CBox模板类添加void setVal(T _val)函数,以便于修改数据

下面给出测试主函数如下:(不可修改)

template<typename T>

void pushBox(istream& in, vector<CBoxObject*>& container, const string& type) {

    T val;

    in >> val;

    container.emplace_back(new CBox<T>(type, val));

}

int main() {

    string type; // 数据类型

    int n, index; // n为输入次数,index为vector数组下标

    cin >> n;

    vector<CBoxObject*> pBoxes;

    pBoxes.reserve(n); // 预先分配足够的空间(pBoxes.size()==0依然成立)

    while (n-- > 0) {

        cin >> type;

        // 根据数据类型分别包装

        if (type == "char") pushBox<char>(cin, pBoxes, type);

        else if (type == "int") pushBox<int>(cin, pBoxes, type);

        else if (type == "double") pushBox<double>(cin, pBoxes, type);

        else if (type == "string") pushBox<string>(cin, pBoxes, type);

        // 我们觉得一个盒子也是可以包装另一个盒子的

        // 为了便捷起见,我们采用盒子指针来表示盒子间的包装关系

        else if (type == "box") {

            cin >> index;

            auto box = new CBox<CBoxObject*>("box", nullptr);

            // 根据index从pBoxes已有的盒子中选择一个用新盒子包装

            if (0 <= index && index < pBoxes.size()) {

                box->setVal(pBoxes[index]);

                // 现实中盒子是不能自己包装自己的

                // 在本题中,如果盒子自己包装自己,则将指针值设置为空

                // 本题暂不考虑链表成环问题

            }

            pBoxes.emplace_back(box);            

        }

        index = (int)pBoxes.size() - 1;

        cout << *pBoxes[index] << endl;

    }

    for (CBoxObject*& box : pBoxes) delete box;

    return 0;

}

在决定使用CBoxObject*原生指针类型作为CBox的模板参数时,你可能会发现一个问题:

a)如果包装的值是"空指针nullptr"(NULL倒不会),则在输出时会出现问题!

b)如果包装值是非空指针,那么一般来说打印指针值是没有什么价值的,我们更关注的是指针所指向的内容。

我们希望能够对T*这样的模板参数类型定义不同处理方式。

通过进一步学习可以了解到c++支持的"模板偏特化"方法:

template<typename T> class CC { ...... };

template<typename T> class CC<T*> { ...... };

template<typename T> class CC<const T*> { ...... };

......

4. 为CBox模板类定义适合以原生指针作为模板参数的特化版本

    由于定义的成员变量为指针类型,且同一对象被new出来后可能被赋予多个所有者,

    为了简化编程,本题不考虑析构函数(使用默认的即可)

(要进一步保障复制和析构安全性,避免内存泄露,可以考虑加入"引用计数指针"进一步完善定义,本题目不作要求)

   本题的特化版本为:

   template <>

   class CBox<CBoxObject *> :public CBoxObject

   {

       CBoxObject *data;

在处理输出时,你可能会写出"cout<<val;"和"cout<<*val;"这样的语句以通用于int*,string*等其它原生指针

如果使用了CBox<T*>,请注意为相应的T类要有输出重载

5. 为CBoxObject类重载输出

输入要求:

参见主函数

输出要求:

输出格式:{type: value}

如果为value为空指针(nullptr),则输出为:{}

输入样例:

10
string hello
int 666
char c
double 3.14
box 3
box 4
box 6
box 6
box 9
box -1

输出样例:

{string: hello}
{int: 666}
{char: c}
{double: 3.14}
{box: {double: 3.14}}
{box: {box: {double: 3.14}}}
{}
{box: {}}
{}
{}

代码示例:

#include<iostream>
#include<iomanip>
#include<cstring>
#include<string> 
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

class CBoxObject
{
protected:
	string type; // 记录类型信息
public:
	CBoxObject(string _type) : type(_type) {}
	virtual void show(ostream&) const = 0; // 用于输出信息
};

ostream& operator << (ostream& out, CBoxObject& rhs)//全局的运算符重载
{
	rhs.show(out);
	return out;
}

ostream& operator << (ostream& out, CBoxObject* rhs)
{
	rhs->show(out);
	return out;
}


template<class T>
class CBox : public CBoxObject
{
protected:
	T data;
public:
	CBox(string type, T dd) : CBoxObject(type), data(dd) {}
	virtual void show(ostream& out) const
	{
		out << '{' << type << ": " << data << '}';
	}
	void setVal(T dd)
	{
		data = dd;
	}
};

template<>
class CBox<CBoxObject*> : public CBoxObject
{
protected:
	CBoxObject* data;
public:
	CBox(string type, CBoxObject* dd) : CBoxObject(type), data(dd) {}
	virtual void show(ostream& out) const
	{
		if (data)
			out << '{' << type << ": " << data << '}';
		else
			out << "{}";
	}
	void setVal(CBoxObject* dd)
	{
		data = dd;
	}
};

template<typename T>
void pushBox(istream& in, vector<CBoxObject*>& container, const string& type)
{
	T val;
	in >> val;
	container.emplace_back(new CBox<T>(type, val));
}
int main() {
	string type; // 数据类型
	int n, index; // n为输入次数,index为vector数组下标
	cin >> n;
	vector<CBoxObject*> pBoxes;
	pBoxes.reserve(n); // 预先分配足够的空间(pBoxes.size()==0依然成立)
	while (n-- > 0) {
		cin >> type;
		// 根据数据类型分别包装
		if (type == "char") pushBox<char>(cin, pBoxes, type);
		else if (type == "int") pushBox<int>(cin, pBoxes, type);
		else if (type == "double") pushBox<double>(cin, pBoxes, type);
		else if (type == "string") pushBox<string>(cin, pBoxes, type);
		// 我们觉得一个盒子也是可以包装另一个盒子的
		// 为了便捷起见,我们采用盒子指针来表示盒子间的包装关系
		else if (type == "box") {
			cin >> index;
			auto box = new CBox<CBoxObject*>("box", nullptr);
			// 根据index从pBoxes已有的盒子中选择一个用新盒子包装
			if (0 <= index && index < pBoxes.size()) {
				box->setVal(pBoxes[index]);
				// 现实中盒子是不能自己包装自己的
				// 在本题中,如果盒子自己包装自己,则将指针值设置为空
				// 本题暂不考虑链表成环问题
			}
			pBoxes.emplace_back(box);
		}
		index = (int)pBoxes.size() - 1;
		cout << *pBoxes[index] << endl;
	}
	for (CBoxObject*& box : pBoxes) delete box;
	return 0;
}

最后一题感觉参考意义不大

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

再给艾克三年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值