Coding In C++, Day11

一、为什么要有模板?
将类型参数化,可以实现算法与类型的分离,编写针对类型更加抽象的函数或者类。
二、函数模板
通用定义:
template<typename 类型形参1, ...>
返回类型 函数模板名 (形参表) { ... }
特化定义:
template<>

返回类型 函数模板名<类型实参1, ...> (形参表) { ... }

/* 函数模板(模板函数)练习
 * */
#include <iostream>
#include <typeinfo>
#include <cstring>
using namespace std;


template<typename T/*类型形式参数表*/>
//typename关键字声明了类型形式参数表,早期这里采用的关键字是class,早期就直接用关键字class来声明类型形式参数, 在这里class就是typename, typename就是class, 没有区别!
T Max (T x, T y) 
{//编译期编译此处时,不进行实际编译,只进行基本的类型检查,当后期有模板的实例要进行编译时,根据实例化时候给出的实际类型参数进行编译,这称为"后期编译"。
//后期编译,在获得实际类型参数时进行编译,也就是说一个模板函数或许在编译期被编译为多个具体的函数。
	cout << typeid (T).name () << endl;
	return x > y ? x : y;
}

// 模板特化
template<>//缺少后部分编译器会报错,部分容错性比较好的编译器能够自动识别同名于模板函数的函数为其特化。
char* Max<char* /*可以省略,编译器可以根据后边括号中的char*隐式推断出来这里的char**/> (char* x, char* y) 
{//当编译期获得实际类型参数是char*时,按照该特化的模板编译。
	return strcmp (x, y) > 0 ? x : y;
}
template<typename T>
void foo (void) {
	T t;
	cout << typeid (t).name () << endl;
}
int main (void) {
	cout << "输入两个整数:" << flush;
	int nx, ny;
	cin >> nx >> ny;
	cout << "最大值:" << Max<int/*类型实际参数*/> (nx, ny) << endl;//获得Max的实际类型参数表后进行编译,这叫做"后期编译"。
	cout << "输入两个字符串:" << flush;
	string sx, sy;
	cin >> sx >> sy;
	cout << "最大值:" << Max (sx, sy) << endl;//编译器自动推断类型实际参数,最终编译函数string Max(string, string);
	cout << "输入两个字符串:" << flush;
	foo<int> ();//编译器不能自动推断类型实际参数,必须显式的给出类型实际参数表。
	foo<double> ();
	foo<string> ();

	char cx[256], cy[256];
	cin >> cx >> cy;
	cout << "最大值:" << Max<char*> (cx, cy) << endl;//编译函数char* Max(chat*, char*);


	return 0;
}


三、类模板
通用定义:
template<typename 类型形参1, ...>
class 类模板名 { ... };
全类特化:
template<>
class 类模板名<类型实参1, ...> { ... };
成员特化:
template<>

返回类型 类模板名<类型实参1, ...>::成员函数名 (形参表) { ... }

/*类模板练习
 * */
#include <iostream>
#include <cstring>
using namespace std;
// 通用模板
template<typename T>
class Comparator {
public:
	Comparator (T x, T y) : m_x (x), m_y (y) {}
	T min (void) const {
		return m_x < m_y ? m_x : m_y;
	}
	T max (void) const {
		return m_x > m_y ? m_x : m_y;
	}
private:
	T m_x;
	T m_y;
};
/*
// 针对char*的全模板特化
template<>
class Comparator<char*> {
public:
	Comparator (char* x, char* y) :
		m_x (x), m_y (y) {}
	char* min (void) const {
		return strcmp (m_x, m_y) < 0 ? m_x : m_y;
	}
	char* max (void) const {
		return strcmp (m_x, m_y) > 0 ? m_x : m_y;
	}
private:
	char* m_x;
	char* m_y;
};
*/
// 针对char*的成员函数特化
template<>
char* Comparator<char*>::min (void) const {
	return strcmp (m_x, m_y) < 0 ? m_x : m_y;
}
template<>
char* Comparator<char*>::max (void) const {
	return strcmp (m_x, m_y) > 0 ? m_x : m_y;
}
int main (void) {
	cout << "输入两个整数:" << flush;
	int nx, ny;
	cin >> nx >> ny;
	Comparator<int> cn (nx, ny);// 编译期使用实际类型参数表进行模板实例化,运行期使用实例化后的类进行对象实例化。
	cout << "最小值:" << cn.min () << endl;
	cout << "最大值:" << cn.max () << endl;
	cout << "输入两个字符串:" << flush;
	string sx, sy;
	cin >> sx >> sy;
	Comparator<string> cs (sx, sy);
	cout << "最小值:" << cs.min () << endl;
	cout << "最大值:" << cs.max () << endl;
	cout << "输入两个字符串:" << flush;
	char cx[256], cy[256];
	cin >> cx >> cy;
	Comparator<char*> cc (cx, cy);
	cout << "最小值:" << cc.min () << endl;
	cout << "最大值:" << cc.max () << endl;
	return 0;
}


四、局部特化

/*
 * 模板的局部特化
 * */
#include <iostream>
using namespace std;
template<typename T1, typename T2>
class A {
public:
	A (void) {
		cout << "A<T1,T2>" << endl;
	}
};
template<typename T1>
class A<T1, int> {
public:
	A (void) {
		cout << "A<T1,int>" << endl;
	}
};
template<>
class A<int, int> {
public:
	A (void) {
		cout << "A<int,int>" << endl;
	}
};
template<typename T>
class B {
public:
	B (void) {
		cout << "B<T>" << endl;
	}
};
template<typename T>
class B<T*> {
public:
	B (void) {
		cout << "B<T*>" << endl;
	}
};
template<typename T>
class B<T[]> {
public:
	B (void) {
		cout << "B<T[]>" << endl;
	}
};
template<typename T1, typename T2, typename T3>
class C {
public:
	C (void) {
		cout << "C<T1,T2,T3>" << endl;
	}
};
template<typename T1, typename T2>
class C<T1, T2, T2> {
public:
	C (void) {
		cout << "C<T1,T2,T2>" << endl;
	}
};
template<typename T1>
class C<T1, T1*, T1*> {
public:
	C (void) {
		cout << "C<T1,T1*,T1*>" << endl;
	}
};
int main (void) {
	// 特化程度高(具体化程度高,模板实例化程度高)的优先
	A<double, double> a1;
	A<double, int> a2;
	A<int, int> a3;
	// 针对指针和数组的特化优先
	B<char> b1;
	B<char*> b2;
	B<char[]> b3;
	// 匹配度高的特化优先
	C<char, short, long> c1;
	C<char, short, short> c2;
	C<char, char*, char*> c3;
	return 0;
}


五、非类型参数和缺省参数
1.非类型参数的实参仅限于常量或者常量表达式。

2.无论类型参数还是非类型参数都可以带有缺省值,而且和函数的缺省参数一样,模板的缺省参数也必须靠右。

#include <iostream>
using namespace std;
template<typename T = int, size_t S = 5>
class Array {
public:
	T& operator[] (size_t i) {
		return m_array[i];
	}
	const T& operator[] (size_t i) const {
		return const_cast<Array&> (*this) [i];
	}
	size_t size (void) const {
		return S;
	}
	friend ostream& operator<< (ostream& os,
		const Array& arr) {
		for (size_t i = 0; i < arr.size (); ++i)
			os << '(' << arr.m_array[i] << ')';
		return os;
	}
private:
	T m_array[S];
};
int main (void) {
	const /*volatile*/ int x = 3, y = 7;//对于具有常属性的变量,编译器在编译期进行优化,会把常属性的变量替换为常量,以图通过立即数来提高访问效率。通过关键字volatile可以取消编译器的这种优化。
	Array<int, x+y> arr;//非类型实际参数只能是常量表达式
	for (size_t i = 0; i < arr.size (); ++i)
		arr[i] = i;
	cout << arr << endl;
	Array<Array<int, 4>, 3> m;
	for (size_t i = 0; i < m.size (); ++i)
		for (size_t j = 0; j < m[i].size (); ++j)
			m[i][j] = i * m[i].size () + j;
	cout << m << endl;
	Array<double> a2;
	Array<> a3;
	return 0;
}

#include <iostream>
using namespace std;

template<typename T>
class A {
public:
	class B {};
};

template<typename T>
void foo (void) {
	typename A<T>::B b;//直接写A<T>::B b;编译报错。因编译期初期不会将模板编译成代码,所以A<T>此时还是一个不明的模板类名称,取一个不明模板类作用域里面的B,在编译器进行模板的语法检查时候被编译器报错。可以通过关键字typename来告诉编译器A<T>是后期编译的一个类型名称。
	//这里的typename不可以换为class.这里的typename关键字是告诉编译器A<T>::B是个类型名称
}


int main (void) {
	foo<int> ();
	return 0;
}


六、有关模板的其它问题

1.从模板继承

/*
 * 类模板中的继承-从类模板继承
 * */
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
	A (const T& t) : m_t (t) {}
	T m_t;
};
template<typename T, typename Y>
class B : public A<T>/*A是模板名称,A<T>是类名称*/ {
public:
	B (const T& t, const Y& y) :
		A<T> (t), m_y (y) {}
	Y m_y;
};
int main (void) {
	B<int, string> b (100, "hello");
	cout << b.m_t << ' ' << b.m_y << endl;
	return 0;
}


2.向模板派生

/*
 * 向模板派生
 * 例如本例程:基类具体类,派生类是类模板
 * 
 * */
#include <iostream>
using namespace std;
template<typename BASE>
class Shape : public BASE {
public:
	void draw (void) const {
		BASE::draw ();
	}
};
class Rect {
public:
	void draw (void) const {
		cout << "绘制矩形..." << endl;
	}
};
class Circle {
public:
	void draw (void) const {
		cout << "绘制圆形..." << endl;
	}
};
int main (void) {
	Shape<Rect> shape1;
	shape1.draw ();
	Shape<Circle> shape2;
	shape2.draw ();
	return 0;
}


3.模板中模板成员

1)模板型成员变量

2)模板型成员函数

3)模板型成员类型(内部类)

4.模板型模板实参

/*
 *模板型成员变量
 */
#include <iostream>
using namespace std;

template<typename T>
class A {
public:
	A (const T& t) : m_t (t) {}
	T m_t;
};

template<typename T, typename Y>
class B {
public:
	B (const T& t, const Y& y) :
		m_a (t), m_y (y) {}
	A<T> m_a;
	Y m_y;
};


int main (void) {
	B<int, string> b (100, "hello");
	cout << b.m_a.m_t << ' ' << b.m_y << endl;
	return 0;
}

/*
 * 模板型成员函数
 * */
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
	A (const T& t) : m_t (t) {}
	/*
	template<typename Y>
	void print (const Y& y) {
		cout << m_t << ' ' << y << endl;
	}
	*/
	template<typename Y>
	void print (const Y& y);
	T m_t;
};
template<typename T>
	template<typename Y>
void A<T>::print (const Y& y) {
	cout << m_t << ' ' << y << endl;
}
int main (void) {
	A<int> a (100);
	a.print<string> ("hello");
	return 0;
}

/*
 * 模板型成员类型(内部类)
 *
 * */
#include <iostream>
using namespace std;
template<typename T, typename Y>
class A {
public:
	A (const T& t, const Y& y) :
		m_t (t), m_b (y) {}
	/*
	template<typename X>
	class B {
	public:
		B (const X& x) : m_x (x) {}
		X m_x;
	};
	*/
	template<typename X> class B;//声明模板B
	T m_t;
	B<Y> m_b;
};
template<typename T, typename Y>
	template<typename X>
class A<T, Y>::B {
public:
	B (const X& x) : m_x (x) {}
	X m_x;
};
int main (void) {
	A<int, string> a (100, "hello");
	cout << a.m_t << ' ' << a.m_b.m_x << endl;
	return 0;
}


/*
 * 模板型模板实参(模板作为模板的实参)
 *
 * */
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
	A (const T& t) : m_t (t) {}
	T m_t;
};

template<typename X, typename Z,
	template<typename T>  class Y/*Y是一个模板*/>//也可以写作template<class X, class Z, template<class T> class Y>
class B {
public:
	B (const X& i, const Z& s) :
		m_i (i), m_s (s) {}
	Y<X> m_i;
	Y<Z> m_s;
};
int main (void) {
	B<int, string, A> b (100, "hello");
	cout << b.m_i.m_t << ' ' << b.m_s.m_t << endl;
	return 0;
}


七、容器和迭代器

/*
 * 基于双向链表的容器的实现
 * 
 * */
#include <iostream>
#include <stdexcept>
#include <cstring>
using namespace std;
// 双向线性链表容器模板
template<typename T>
class List {
public:
	// 构造、析构、拷贝构造、拷贝赋值
	List (void) : m_head (NULL), m_tail (NULL) {}
	~List (void) {
		clear ();
	}
	List (const List& that) : m_head (NULL),
		m_tail (NULL) {
		for (Node* node = that.m_head; node;
			node = node->m_next)
			push_back (node->m_data);
	}
	List& operator= (const List& that) {
		if (&that != this) {
			List list (that);
			swap (m_head, list.m_head);
			swap (m_tail, list.m_tail);
		}
		return *this;
	}
	// 获取首元素
	T& front (void) {
		if (empty ())
			throw underflow_error ("链表下溢!");
		return m_head->m_data;
	}
	const T& front (void) const {
		return const_cast<List*> (this)->front ();
	}
	// 向首部压入
	void push_front (const T& data) {
		m_head = new Node (data, NULL, m_head);
		if (m_head->m_next)
			m_head->m_next->m_prev = m_head;
		else
			m_tail = m_head;
	}
	// 从首部弹出
	void pop_front (void) {
		if (empty ())
			throw underflow_error ("链表下溢!");
		Node* next = m_head->m_next;
		delete m_head;
		m_head = next;
		if (m_head)
			m_head->m_prev = NULL;
		else
			m_tail = NULL;
	}
	// 获取尾元素
	T& back (void) {
		if (empty ())
			throw underflow_error ("链表下溢!");
		return m_tail->m_data;
	}
	const T& back (void) const {
		return const_cast<List*> (this)->back ();
	}
	// 向尾部压入
	void push_back (const T& data) {
		m_tail = new Node (data, m_tail);
		if (m_tail->m_prev)
			m_tail->m_prev->m_next = m_tail;
		else
			m_head = m_tail;
	}
	// 从尾部弹出
	void pop_back (void) {
		if (empty ())
			throw underflow_error ("链表下溢!");
		Node* prev = m_tail->m_prev;
		delete m_tail;
		m_tail = prev;
		if (m_tail)
			m_tail->m_next = NULL;
		else
			m_head = NULL;
	}
	// 删除所有匹配元素
	void remove (const T& data) {
		for (Node* node = m_head, *next; node;
			node = next) {
			next = node->m_next;
			if (equal (node->m_data, data)) {
				if (node->m_prev)
					node->m_prev->m_next =
						node->m_next;
				else
					m_head = node->m_next;
				if (node->m_next)
					node->m_next->m_prev =
						node->m_prev;
				else
					m_tail = node->m_prev;
				delete node;
			}
		}
	}
	// 清空
	void clear (void) {
		for (Node* next; m_head; m_head = next) {
			next = m_head->m_next;
			delete m_head;
		}
		m_tail = NULL;
	}
	// 判空
	bool empty (void) const {
		return ! m_head && ! m_tail;
	}
	// 获取大小
	size_t size (void) const {
		size_t count = 0;
		for (Node* node = m_head; node;
			node = node->m_next)
			++count;
		return count;
	}
	// 插入输出流
	friend ostream& operator<< (ostream& os,
		const List& list) {
		for (Node* node = list.m_head; node;
			node = node->m_next)
			os << *node;
		return os;
	}
private:
	// 节点
	class Node {
	public:
		Node (const T& data = 0, Node* prev = NULL,
			Node* next = NULL) : m_data (data),
			m_prev (prev), m_next (next) {}
		friend ostream& operator<< (ostream& os,
			const Node& node) {
			return os << '(' << node.m_data << ')';
		}
		T m_data; // 数据
		Node* m_prev; // 前指针
		Node* m_next; // 后指针
	};
	bool equal (const T& a, const T& b) const {
		return a == b;
	}
	Node* m_head; // 头指针
	Node* m_tail; // 尾指针
public:
	// 正向迭代器
	class Iterator {
	public:
		Iterator (Node* head = NULL,
			Node* tail = NULL, Node* node = NULL) :
			m_head (head), m_tail (tail),
			m_node (node) {}
		bool operator== (const Iterator& it) const {
			return m_node == it.m_node;
		}
		bool operator!= (const Iterator& it) const {
			return ! (*this == it);
		}
		Iterator& operator++ (void) {
			if (m_node)
				m_node = m_node->m_next;
			else
				m_node = m_head;
			return *this;
		}
		const Iterator operator++ (int) {
			Iterator old = *this;
			++*this;
			return old;
		}
		Iterator& operator-- (void) {
			if (m_node)
				m_node = m_node->m_prev;
			else
				m_node = m_tail;
			return *this;
		}
		const Iterator operator-- (int) {
			Iterator old = *this;
			--*this;
			return old;
		}
		T& operator* (void) const {
			return m_node->m_data;
		}
		T* operator-> (void) const {
			return &**this;
		}
	private:
		Node* m_head;
		Node* m_tail;
		Node* m_node;
		friend class List;
	};
	Iterator begin (void) {
		return Iterator (m_head, m_tail, m_head);
	}
	Iterator end (void) {
		return Iterator (m_head, m_tail);
	}
	Iterator insert (Iterator loc, const T& data) {
		if (loc == end ()) {
			push_back (data);
	   		return Iterator (m_head, m_tail,m_tail);
		}
		else {
			Node* node = new Node (data,
				loc.m_node->m_prev, loc.m_node);
			if (node->m_prev)
				node->m_prev->m_next = node;
			else
				m_head = node;
			node->m_next->m_prev = node;
			return Iterator (m_head, m_tail, node);
		}
	}
	Iterator erase (Iterator loc) {
		if (loc == end ())
			throw invalid_argument ("无效迭代器!");
		if (loc.m_node->m_prev)
			loc.m_node->m_prev->m_next =
				loc.m_node->m_next;
		else
			m_head = loc.m_node->m_next;
		if (loc.m_node->m_next)
			loc.m_node->m_next->m_prev =
				loc.m_node->m_prev;
		else
			m_tail = loc.m_node->m_prev;
		Node* next = loc.m_node->m_next;
		delete loc.m_node;
		return Iterator (m_head, m_tail, next);
	}
};
// 针对const char*的特化
template<>
bool List<const char*>::equal (const char* const& a,
	const char* const& b) const {
	return strcmp (a, b) == 0;
}
// 测试用例
int main (void) {
	try {
		List<int> list1;
		list1.push_front (20);
		list1.push_front (10);
		list1.push_back (30);
		list1.push_back (40);
		cout << list1 << endl;
		cout << list1.front () << ' ' <<
			list1.back () << endl;
		list1.pop_front ();
		list1.pop_back ();
		cout << list1 << endl;
		++list1.front ();
		--list1.back ();
		cout << list1 << endl;
		list1.push_back (21);
		list1.push_back (25);
		list1.push_back (21);
		list1.push_back (21);
		cout << list1 << endl;
		list1.remove (21);
		cout << list1 << endl;
		List<int> list2 = list1;
		cout << list2 << endl;
		list2.back () = 100;
		cout << list2 << endl;
		cout << list1 << endl;
		list2 = list1;
		cout << list2 << endl;
		list2.front () = 100;
		cout << list2 << endl;
		cout << list1 << endl;
		cout << list1.size () << endl;
		list1.clear ();
		cout << list1 << endl;
		cout << boolalpha << list1.empty () << endl;
//		List<string> list3;
		List<const char*> list3;
		list3.push_back ("beijing");
		list3.push_back ("tianjin");
		list3.push_front ("tianjin");
		list3.push_back ("shanghai");
		list3.push_back ("beijing");
		cout << list3 << endl;
		list3.remove (string ("beijing").c_str ());
		cout << list3 << endl;
		for (List<const char*>::Iterator it =
			list3.begin (); it != list3.end ();
			++it)
			cout << *it << ' ';
		cout << endl;
		List<const char*>::Iterator it =
			list3.begin ();
		it++;
		it = list3.insert (it, "chongqing");
		cout << list3 << endl;
		list3.erase (it);
		cout << list3 << endl;
	}
	catch (exception& ex) {
		cout << ex.what () << endl;
		return -1;
	}
	return 0;
}












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C和C++的安全编码是指在编写C和C++代码时,采取一系列的措施来确保代码的安全性和防止常见的安全漏洞。由于C和C++是底层的编程语言,它们允许对内存直接进行操作,这也使得它们容易受到各种安全威胁的攻击。 在进行安全编码时,有几个关键的原则需要遵循。首先是验证输入。由于输入数据往往是来自外部,我们需要对输入进行验证,以确保它们符合预期的格式和范围。这样可以防止缓冲区溢出和格式化字符串漏洞等攻击。 其次,应该正确地管理内存。C和C++允许直接控制内存的分配和释放,但这也意味着需要手动管理内存的生命周期。如果没有正确地分配和释放内存,会导致内存泄漏和非法内存访问等问题。因此,务必要仔细检查并指定正确的内存操作。 此外,还应注意避免使用不安全的函数和功能。一些函数和功能可能存在安全风险,如strcpy和scanf等。应该使用更安全的替代函数,如strncpy和fgets等,以提高代码的安全性。 最后,代码的安全性也需要经过不断的测试和审查。通过进行静态代码分析和动态测试,可以发现和纠正代码中的潜在安全问题。此外,代码审查也是非常重要的,通过互相审查可以找到潜在的漏洞和错误。 总而言之,C和C++的安全编码需要遵循验证输入、正确管理内存、避免使用不安全函数和功能以及进行测试和审查等原则。只有通过采取适当的安全措施,才能确保代码的安全性并防止潜在的安全漏洞。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值