C++程序设计基础【四】(泛函编程和异常处理)

C++程序设计基础【四】

  • 一、泛型编程:模板
    • 1、函数模板
      • 1.比较同一类型数值大小
      • 2.打印数组
      • 3.显式类型确定
      • 4.模板特化
    • 2、类模板
      • 1.接口
      • 2.实现
      • 3.友元函数
      • 4.别名
      • 5.继承
  • 二、异常处理
    • 1.错误处理的传统方法
      • 1.让运行环境中止程序
      • 2.请求运行时环境中止程序
      • 3.错误检查
      • 4.使用函数返回值进行错误检查
    • 2.异常处理方法
      • 1.try-catch语句块
      • 2.三种模式
        • 模式1
        • 模式2
        • 模式3
      • 3.throw语句
      • 4.多条catch子句
      • 5.通用catch子句
      • 6.异常传播
      • 7.重新抛出异常
    • 3.异常规范
      • 1.任何异常
      • 2.预定义异常
      • 3.无异常
    • 4.栈展开
      • 1.程序内存
      • 2.压入和弹出栈内存
      • 3.栈展开的效果
    • 5.类中的异常
      • 1.构造函数中的异常
        • 1.在栈内存中创建对象
          • 1.在构造函数中不抛出异常
          • 2.在构造函数中抛出异常
        • 2.在堆内存中对象的部分创建
          • 1.在构造函数中不抛出异常
          • 2.在构造函数中抛出异常
          • 3.使用智能指针进行内存管理
          • 4.构造函数中try-catch语句块:function-try语句块
      • 2.析构函数中的异常
    • 6.标准异常类
      • 1.逻辑错误
      • 2.运行时错误
      • 3.其他类
      • 4.使用标准异常类

一、泛型编程:模板

1、函数模板

模板函数的定义可以放在接口文件中

1.比较同一类型数值大小

template <typename T, typename U, ... , typename C>
void functionName (U first , ... , Z last)
{
	...
}

2.打印数组

template <typename T, int N>
void functionName (T (&array)[N])
{
	...
}

3.显式类型确定

将不同类型的数值转换为同一类型

xxx <double>(A,B)

4.模板特化

字符串没有定义<,使用模板特化解决

template <typename T>
void functionName (const T& first , const T& second)
{
	...
}

2、类模板

一般将声明放在.h文件中,将定义放在.cpp文件中
如果要独立编译,则要在template前加export

1.接口

template <typename T>
class Name
{
	private:
		T data;
	public:
		Name();
		T get()const;
		voic set(T data);
}

2.实现

template <typename T>
T name <T>::get()const
{
	return data;
}
template <typename T>
void name <T>::set(T d)
{
	data = d;
}

3.友元函数

模板类的声明可以包含友元函数

4.别名

有时可以使用关键字typedef为模板类定义别名

typedef stack <string,int> siStack;

5.继承

//模板类
template <typename T>
class First
{
	...
}
//继承类
template <typename T>
class Second:public First <T>
{
	...
}

二、异常处理

1.错误处理的传统方法

1.让运行环境中止程序

Nothing to do,当出现异常时让程序中止

2.请求运行时环境中止程序

在可能出现错误的地方打印,用assert宏中止程序抛出异常

3.错误检查

判断为会出现异常处,添加跳过语法,防止抛出异常

4.使用函数返回值进行错误检查

根据不同情况,返回不同值

2.异常处理方法

1.try-catch语句块

try
{
	//可能产生异常的代码
}
catch
{
	//处理异常的代码
}

2.三种模式

模式1

try-catch语句块完全包含在一个函数中(不常见)

int main()
{
	try
	{
		...
		throw xxx;
		...
	}
	catch (type xxxx)
	{
		...
	}
	return 0;
}

模式2

由try中函数抛出异常(推荐)

int main()
{
	try
	{
		...
		xxxxx();
		...
	}
	catch (type xxxx)
	{
		...
	}
	return 0;
}
type xxxxx (...)
{
	...
	throw xxx;
	...
	return xxxxxx;
}

异常处理方法的优点之一是我们可以设计能够抛出异常的函数。调用方负责处理异常

模式3

当被调用函数属于独立实体时(如类中的成员函数)时,出现异常,被调用函数无法继续执行剩余的代码,则需要这两个函数中都有try-catch语句块,catch子句重新抛出异常给主调函数,以便主调函数捕获该异常

3.throw语句

throw语句必须直接或者间接包含在try语句中

4.多条catch子句

一个函数可能抛出多种不同类型异常的情况,那么catch子句也要对应

try
{
	throw A;
	...
	throw B;
}
catch (type1 obj1)
{
	Handle xxxx;
}
catch (type2 obj2)
{
	Handle xxxxx;
}

5.通用catch子句

catch子句只能捕获其参数类型的异常

6.异常传播

如果未在抛出异常的位置捕获和处理异常,则该异常将被自动传播到函数调用层次结构中的上一个函数

7.重新抛出异常

try
{
	...
}
catch (type A)
	...//某些处理工作
	throw;//重新抛出异常给主调函数

3.异常规范

给别人用时,在函数头中添加表达式,以告诉用户如果在主调函数中捕捉异常

1.任何异常

函数可以抛出任何异常

2.预定义异常

如果函数的设计者和用户的不同,必须在函数头部定义函数抛出的异常
规范为函数声明后加上throw(xxx)

3.无异常

向用户声明此函数不引发异常
规范为函数声明后加上throw()

4.栈展开

1.程序内存

2.压入和弹出栈内存

3.栈展开的效果

由于函数返回或者抛出的异常而从占内存中弹出条目被称为栈展开。在栈展开期间,函数的参数和本地对象会通过调用其析构函数自动销毁(堆中可能会内存泄漏)
为了避免内存泄漏,必须使对象成为定义它们的函数的本地对象

5.类中的异常

1.构造函数中的异常

1.在栈内存中创建对象

1.在构造函数中不抛出异常
2.在构造函数中抛出异常

2.在堆内存中对象的部分创建

1.在构造函数中不抛出异常
2.在构造函数中抛出异常
3.使用智能指针进行内存管理
4.构造函数中try-catch语句块:function-try语句块

2.析构函数中的异常

必须避免在析构函数中引发异常

6.标准异常类

1.逻辑错误

逻辑错误与函数先决条件相关
要使用逻辑错误类,需要包含头文件

2.运行时错误

运行时错误与函数的后置条件相关
要使用运行时错误类,需要包含头文件

3.其他类

4.使用标准异常类

使用或者头文件中定义的标准异常类的对象

你可能感兴趣的:(C++开发工程师之路,c++,开发语言)