侧边栏壁纸
  • 累计撰写 125 篇文章
  • 累计创建 16 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录
C++   

C++学习--进阶Ⅰ

异常处理

在程序执行时出现错误,例如文件路径有误造成无法读取,异常处理提供了一种转移程序控制权的方法。

C++ 的异常处理流程:在 try 中的代码抛出异常,由 catch 进行捕获异常。异常可以是系统自带的类型,也可以利用 throw 主动抛出异常,可以对异常类 exception 进行继承重载来定义新异常

代码中每次执行可能会抛出不同类型异常可以通过多个 catch 来捕获分别做出处理。

try
{}catch( ExceptionName e1 )
{}catch( ExceptionName e2 )
{}catch( ExceptionName e3 )
{}

throw 抛出异常

使用 throw 在任何地方都可抛出异常。throw 语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常类型

if( b == 0 )
{
     throw "Division by zero condition!";
}
return (a/b);

捕获异常

catch 块跟在 try 块后面,用于捕获异常,还可以指定想要捕捉的异常类型

try
{}catch( ExceptionName e )
{
  // 处理 ExceptionName 异常的代码
}

标准异常

在 C++ 的 <exception> 中已经定义了在程序中标准的异常。

定义新的异常

可以通过继承重载 exception 类来定义新异常

struct MyException : public exception
{
  const char * what () const throw ()
  {
    return "C++ Exception";
  }
};

throw MyException();

可以发现这里用的是结构体继承,在 C++ 中结构体的功能有极大的扩展,拥有了功能,唯一的区别在默认的继承访问权限struct是publicclass是private。但是我们依旧将类变量成员结构体变量数据。并且类与结构体之间是可以相互继承的。

  • const char * :是返回类型,一个指向常量字符的指针
  • what() :异常类提供的一个公共方法,它已被所有子异常类重载
  • const :声明为const函数,
  • throw () :声明该函数不抛出异常

动态内存

C++ 程序中的内存分为以下五个部分:

  • 栈区:由编译器在需要时自动分配,不需要时自动清除的变量存储区。通常存放局部变量、函数参数等。
  • 堆区:是由 new 分配的内存块,newdelete 对应。如果没有手动释放掉,资源将由操作系统在程序结束后自动回收。
  • 自由存储区:是由 malloc 等分配的内存块,用free来释放,和堆十分相似,是同一块区域(其实 new 底层调用的是 malloc)。
  • 全局/静态存储区:全局变量和静态变量被分配到同一块内存中。
  • 常量存储区:这是一块特殊存储区,里边存放常量,不允许修改。

new 和 delete 运算符

  • new:为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。‘
  • delete删除之前由 new 运算符分配的内存
double* pvalue  = NULL;    // 初始化为 null 的指针
if( !(pvalue  = new double ))	// 为变量请求内存,并检查是否成功分配
{
   cout << "Error: out of memory." <<endl;
   exit(1);
}
*pvalue = 29494.99;		// 在分配的地址存储值
delete pvalue;     // 释放 pvalue 所指向的内存

模板

模板是泛型编程的基础,泛型编程即以一种独立于任何特定数据类型的方式编写代码。即在函数或类定义时并没有固定数据类型,而是在使用时指定。

函数模板

一般形式如:

template <typename type> 
ret-type func-name(parameter list)
{
}

type 是函数所使用的数据类型的占位符名称。例子如下:

template <typename T>   // 占位符为 T,在被调用时才能确定
inline T const& Max (T const& a, T const& b) 	// 创建一个内联函数 **Max**,返回类型为 T,形参为常值引用调用
{ 
    return a < b ? b:a; 
} 

Max(int 1,int 2)

类模板

对类的定义也是类似的手法,可以定义相同的操作,拥有不同数据类型的成员属性。

template <typename T>	// 申明为类模型,以下遇到 T 后表示为一种泛型
class Complex{
public:
    //构造函数
    Complex(T a, T b)
    {
        this->a = a;
        this->b = b;
    }
    
    //运算符重载
    Complex<T> operator+(Complex &c)
    {
        Complex<T> tmp(this->a+c.a, this->b+c.b);
        return tmp;
    }
        
private:
    T a;
    T b;
}

int main()
{
    //对象的定义,必须声明模板类型,因为要分配内容
    Complex<int> a(10,20);  
    Complex<int> b(20,30);
    Complex<int> c = a + b;
    
    return 0;
}

预处理器

预处理器是指示编译器在实际编译之前所需完成的预处理内容。所有的预处理器指令都是以井号(#)开头,只有空格字符可以出现在预处理指令之前。预处理指令不是 C++ 语句,所以它们不会分号(;)结尾

#define            定义一个预处理宏
#undef            取消宏的定义

#if                   编译预处理中的条件命令,相当于C语法中的if语句
#ifdef              判断某个宏是否被定义,若已定义,执行随后的语句
#ifndef            与#ifdef相反,判断某个宏是否未被定义
#elif                若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if
#else              与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else
#endif             #if, #ifdef, #ifndef这些条件命令的结束标志.

#define 预处理

#define 预处理指令用于创建符号常量。该符号常量通常称为

#define PI 3.14159
 
int main ()
{
    cout << "Value of PI :" << PI << endl;
}

#define 还可以来定义一个带有参数的宏

#define MIN(a,b) (a<b ? a : b)
 
int main ()
{
   int i, j;
   i = 100;
   j = 30;
   cout <<"较小的值为:" << MIN(i, j) << endl;
}

条件编译

有选择地对部分程序源代码进行编译

#ifdef NULL
   #define NULL 0
#endif

# 和 ## 运算符

# 字符串化的意思,出现在宏定义中的#是把跟在后面的参数转换成一个字符串

#define MKSTR( x ) #x
 
int main ()
{
    cout << MKSTR(HELLO C++) << endl;		// 转换成了:cout << "HELLO C++" << endl;
}

## 连接符号,把参数连在一起

#define concat(a, b) a ## b
int main()
{
   int xy = 100;
   cout << concat(x, y);	// 转换成了:cout << xy;
}
0

评论区