北京大学程序设计MOOC作业详解-07-输入输出和模板

北京大学程序设计MOOC作业详解-07-输入输出和模板

话不多说,直接上代码,有问题请留言。

第一题:

template <class T>
T SumArray(
	T* begin, T* end) {
	T ret = *begin++;
	for (; begin != end; ++begin) {
		ret += *begin;
	}
	return ret;
}

需要注意的是:由于不同类型间初始化的方式不同,所以在使用模板初始化变量时,一定要在声明时立即初始化。然后,*begin++;是需要注意的,这个运算要从前往后看,首先解引用得到第一个元素的值,然后指针往后移一位,参见《C++ Primer》的内容:
在这里插入图片描述

第二题:

template<class T, class Func>
void MyForeach(T* begin, T* end, Func func) {
	for (; begin != end; ++begin) {
		func(*begin);
	}
}

需要注意的是:如果是迭代器类型,函数模板的类型请声明为T,然后参数用T*;如果是函数指针类型,就直接声明Func,不再加指针标识符Func*。

这是和调用有关的,因为指针还要解引用,如果直接声明T那没法解引用(编译期);而函数指针不需要解引用,函数名就是函数指针,直接用函数名调用。

第三题:

template<class T, class F>
T* Filter(T* begin, T* end, T* itr, F func) {
	T* ret = itr;
	for (; begin != end; ++begin) {
		if (func(*begin)) {
			*ret++ = *begin;
		}
	}
	return ret;
}

需要注意的是:这个题比较重要,先看Filter的调用方式:

string as1[5] = {"Tom","Mike","Jack","Ted","Lucy"};
string as2[5];
string * p = Filter(as1,as1+5,as2,LongerThan3);
for(int i = 0;i < p - as2; ++i)
	cout << as2[i];

从上述调用代码可知,前两个参数应是迭代器;第三个参数不应该变,是接收过滤值的首地址;第四个参数是比较器;返回值是过滤值的末尾指针

所以,最开始的初值,设为T* ret = itr;,但是迭代器itr不会改变,指向首地址。

第四题:

这个题需要详细分析

在这里插入图片描述
在这里插入图片描述

第四题分析:

首先,MyCin是用无参构造的方式实例化对象的。并且还能支持输入,所以必须重载输入运算符,且是直接用iostream库中的cin进行输入。由于可以连续输入,所以输入函数必须返回引用,因此声明如下:

MyCin& operator>>(int& v);

这里和一般的重载输入运算符不同,常见的重载输入运算符函数如下:

friend istream& operator>>(istream& is, int& v);

为什么会不同呢?因为这里不是用istream的输入流输入的,而是用MyCin的对象完成输入的,所以不传入istream&参数,而是在函数里直接用cin。

此外,还需要思考while(cin >> n);为什么能起作用。首先while是要先判断一个逻辑运算的,也就是cin输入是否合法(到文件尾)。这说明:cin对象要有一个到bool逻辑的强制类型转换方法。因此,MyCin的设计也要有类型转换运算符函数,这就要有一个bool的成员变量,来记录输入是否合法,并返回这个变量

AC代码如下:

public:
    bool isValid;

    MyCin() : isValid(true) { }

    MyCin& operator>>(int& v) {
        cin >> v;
        if (v == -1) {
            isValid = false;
        }
        return *this;
    }

    operator bool() {
        return isValid;
    }

第五题:

这个题也要详细分析。
在这里插入图片描述
在看测试代码之前,先了解一些关于输入流迭代器istream_iterator的知识:
在这里插入图片描述
从这里可以知道,构造函数时就要输入,这说明成员变量至少要有能存储输入信息的数据结构,可以是变量,也可也是数组,这要看后面的内容。
在这里插入图片描述
从这个例子我们可以知道,如果没有执行++,则只会输入一个数据,并不会输入第二个数据,这仍然不能确定是用变量还是用数组存储。按照队列的结构,++运算符可以理解成移动头指针,不一定不代表未读取,再接着看例子吧。
在这里插入图片描述
从这个例子来看,仍然可以用队列进行存储,但是题目并没有给出队列的头文件,也无法自己在非代码填空区填写队列代码。那我们来参考一下STL的实现吧:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
综上所述,可以知道是用变量存储的,且每次移动都伴随着一次输入,而解引用则是返回上一次输入的值。为了避免第一次就解引用,而没用输入,所以要在构造函数里就完成一次输入

AC代码如下:

template <class T>
class CMyistream_iterator
{
	T value{};
	istream& istr;
public:
	CMyistream_iterator(istream& is) : istr(is) {
		istr >> value;
	}

	void operator++(int) {
		istr >> value;
	}

	T operator*() {
		return value;
	}
};

一个小技巧,如果在模板里,不知道初始值是什么,就写:T value{};表示默认值。

第六题:

模板类基础用法,AC代码如下:

template <class T>  
class myclass {
private:
	T* p;
	int size;

public:
	myclass(const T* _p, int _size) : size(_size), p(new T[_size]()) {
		for (int i = 0; i < size; ++i) {
			p[i] = _p[i];
		}
	}
	~myclass( ) {
		delete [] p;
	}
	void Show()
	{
		for( int i = 0;i < size;i ++ ) {
			cout << p[i] << ",";
		}
		cout << endl;
	}
};

第七题:

template <class T1,class T2>
void mysort(
    T1* begin, T1* end, T2 cmp
) {
    for (T1* itr1 = begin; end != itr1; ++itr1) {
        for (T1* itr2 = itr1 + 1; end != itr2; ++itr2) {
            if (!cmp(*itr1, *itr2)) {
                T1 temp = *itr1;
                *itr1 = *itr2;
                *itr2 = temp;
            }
        }
    }
}

从这个代码可以知道,为什么自定义排序必须支持比大小,或者支持小于运算符。这里用的是冒泡排序,如果是快速排序或者归并排序,也差不多,主要是调用比较函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值