【一天从C到C++】高级篇

目录

1.文件和流

2.异常处理

3.动态内存分配

4.命名空间

5.模板

6.预处理器

7.信号处理


1.文件和流

 在头文件<fstream>中

打开文件: void open(const char *filename, ios::openmode mode); 其中打开模式如下:

模式标志描述
ios::app追加模式。所有写入都追加到文件末尾。
ios::ate文件打开后定位到文件末尾。
ios::in打开文件用于读取。
ios::out打开文件用于写入。
ios::trunc如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。

关闭文件:  void close();

写入文件 :  <<

读取文件:   >>

#include <fstream>
#include <iostream>
using namespace std;
 
int main ()
{
    
   char data[100];
 
   // 以写模式打开文件
   ofstream outfile;
   outfile.open("afile.dat");
 
   cout << "Writing to the file" << endl;
   cout << "Enter your name: "; 
   cin.getline(data, 100);
 
   // 向文件写入用户输入的数据
   outfile << data << endl;
 
   cout << "Enter your age: "; 
   cin >> data;
   cin.ignore();
   
   // 再次向文件写入用户输入的数据
   outfile << data << endl;
 
   // 关闭打开的文件
   outfile.close();
 
   // 以读模式打开文件
   ifstream infile; 
   infile.open("afile.dat"); 
 
   cout << "Reading from the file" << endl; 
   infile >> data; 
 
   // 在屏幕上写入数据
   cout << data << endl;
   
   // 再次从文件读取数据,并显示它
   infile >> data; 
   cout << data << endl; 
 
   // 关闭打开的文件
   infile.close();
 
   return 0;
}

文件位置指针:

// 定位到 fileObject 的第 n 个字节(假设是 ios::beg)
fileObject.seekg( n );
 
// 把文件的读指针从 fileObject 当前位置向后移 n 个字节
fileObject.seekg( n, ios::cur );
 
// 把文件的读指针从 fileObject 末尾往回移 n 个字节
fileObject.seekg( n, ios::end );
 
// 定位到 fileObject 的末尾
fileObject.seekg( 0, ios::end );

2.异常处理

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
  • try: try 块中的代码标识可能被激活的特定异常。它后面通常跟着一个或多个 catch 块。

如果 try 块在不同的情境下会抛出不同的异常,这个时候可以尝试罗列多个 catch 语句,用于捕获不同类型的异常。

try
{
   // 保护代码
}catch( ExceptionName e1 )
{
   // catch 块
}catch( ExceptionName e2 )
{
   // catch 块
}catch( ExceptionName eN )
{
   // catch 块
}

C++标准异常:

3.动态内存分配

内存的申请和释放分别为new和delete。

需要注意数组的内存的申请方式:

一维数组:

// 动态分配,数组长度为 m
int *array=new int [m];
 
//释放内存
delete [] array;

二维数组:

int **array
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i<m; i++ )
{
    array[i] = new int [n]  ;
}
//释放
for( int i=0; i<m; i++ )
{
    delete [] array[i];
}
delete [] array;

三维数组的话就再套一层!

对象的内存分配

#include <iostream>
using namespace std;
 
class Box
{
   public:
      Box() { 
         cout << "调用构造函数!" <<endl; 
      }
      ~Box() { 
         cout << "调用析构函数!" <<endl; 
      }
};
 
int main( )
{
   Box* myBoxArray = new Box[4];
 
   delete [] myBoxArray; // 删除数组
   return 0;
}

4.命名空间

定义一个命名空间;

namespace namespace_name {
   // 代码声明
}

命名空间可以不连续,如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称,则仍然需要声明该名称。也就是说只要命名空间的名字相同就是在同一个命名空间,多次声明就相当于在之前的中添加。比如上面这个命名空间定义可以是定义一个新的命名空间,也可以是为已有的命名空间增加新的元素。

此外,命名空间可以嵌套;

namespace namespace_name1 {
   // 代码声明
   namespace namespace_name2 {
      // 代码声明
   }
}

也可以这样嵌套:

// 访问 namespace_name2 中的成员
using namespace namespace_name1::namespace_name2;
 
// 访问 namespace:name1 中的成员
using namespace namespace_name1;

嵌套之后,声明外部的命名空间的时候,也就自然包含了内部的命名空间。

5.模板

模板是一种对类型进行参数化的工具;通常有两种形式:函数模板和类模板;

函数模板 针对仅参数类型不同的函数;类模板 针对仅数据成员和成员函数类型不同的类。

使用模板的目的就是能够让程序员编写与类型无关的代码。

6.预处理器

预处理以井号(#)开头,比如 #include、#define、#if、#else、#line 等,是指编译器在实际编译之前所需完成的预处理。

需要知道条件编译

#ifdef   #ifndef  #endif 等等

此外,#可以当做运算符使用

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

## 连接符号,把参数连在一起。将多个 Token 连接成一个 Token。

#include <iostream>
using namespace std;

#define MKSTR( x ) #x
#define concat(a, b) a ## b
int main()
{
    cout << MKSTR(hello) << endl;
    cout << concat("good","morning") << endl;
    return 0;
}

C++中还有一些预定义宏(C里也有),这些预定义宏在调试的时候很有用。因为他们打印出代码比较详细的信息,常用来打印log。

__LINE__这会在程序编译时包含当前行号。
__FILE__这会在程序编译时包含当前文件名。
__DATE__这会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。
__TIME__这会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。
#include <iostream>
using namespace std;

int main()
{
    cout << "Value of __LINE__ : " << __LINE__ << endl;
    cout << "Value of __FILE__ : " << __FILE__ << endl;
    cout << "Value of __DATE__ : " << __DATE__ << endl;
    cout << "Value of __TIME__ : " << __TIME__ << endl;

    return 0;
}

7.信号处理

信号是一种软件中断,一种向进程传递有关其他进程,操作系统和硬件状态的信息的方法。信号是一种中断,因为它可以改变程序的流程。当信号传递给进程时,进程将停止其执行的操作,处理或忽略信号,或者在某些情况下终止,取决于信号。

如果学过微控制器,就很容易理解这里说的信号,其实就是和中断请求类似。无论要捕获什么信号,都必须使用 signal 函数来注册信号,并将其与信号处理程序相关联。语法如下:

void (*signal (int sig, void (*func)(int)))(int); 

包含两个参数,一个是信号编号(有宏定义的,下边),另一个是信号处理函数的指针(信号处理函数的名字就行)。

常见信号(编号)宏定义如下:

信号描述
SIGABRT程序的异常终止,如调用 abort
SIGFPE错误的算术运算,比如除以零或导致溢出的操作。
SIGILL检测非法指令。
SIGINT程序终止(interrupt)信号。
SIGSEGV非法访问内存。
SIGTERM发送到程序的终止请求。

 可以使用函数 raise() 生成信号,该函数带有一个整数信号编号作为参数。下面的代码用来捕获SIGINT信号,并在三次循环之后生成一个SIGINT信号来让其捕获。也可以不用raise来生成信号,手动ctrl+c也可以生成SIGINT信号。

#include <iostream>
#include <csignal>
#include <windows.h>

using namespace std;

void signalHandler(int signum)
{
    cout << "Interrupt signal (" << signum << ") received.\n";

    // 清理并关闭
    // 终止程序 

    exit(signum);

}

int main()
{
    int i = 0;
    // 注册信号 SIGINT 和信号处理程序
    signal(SIGINT, signalHandler);

    while (++i) {
        cout << "Going to sleep...." << endl;
        if (i == 3) {
            raise(SIGINT);
        }
        Sleep(1);
    }

    return 0;
}

学习平台:菜鸟教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值