高级教程
1. 文件和流
数据类型 | 描述 |
---|---|
ofstream | 该数据类型表示输出文件流,用于创建文件并向文件写入信息。 |
ifstream | 该数据类型表示输入文件流,用于从文件读取信息。 |
fstream | 该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。 |
要在 C++ 中进行文件处理,必须在 C++ 源代码文件中包含头文件 <iostream> 和 <fstream>。
void open(const char *filename, ios::openmode mode);
void close();
模式标志 | 描述 |
---|---|
ios::app | 追加模式。所有写入都追加到文件末尾。 |
ios::ate | 文件打开后定位到文件末尾。 |
ios::in | 打开文件用于读取。 |
ios::out | 打开文件用于写入。 |
ios::trunc | 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。 |
// 接收流数据
char data[100];
// 以写模式打开文件
ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );
// 向文件写入用户输入的数据
outfile << data << endl;
// 关闭打开的文件
outfile.close();
// 以读模式打开文件
ifstream infile;
infile.open("afile.dat");
cout << "Reading from the file" << endl;
infile >> data;
// 在屏幕上写入数据
cout << data << endl;
// 关闭打开的文件
infile.close();
文件位置指针
istream 和 ostream 都提供了用于重新定位文件位置指针的成员函数。这些成员函数包括关于 istream 的 seekg(“seek get”)和关于 ostream 的 seekp(“seek put”)。
// 定位到 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. 异常处理
C++ 标准的异常
C++ 提供了一系列标准的异常,定义在 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:
下表是对上面层次结构中出现的每个异常的说明:
// 自定义Exception
struct MyException : public exception
{
const char * what () const throw ()
{
return "C++ custom defined Exception";
}
};
int main()
{
try
{
throw "string exception";
throw MyException();
}
catch(const char* e)
{
std::cerr << e << '\n';
}
catch(MyException& e)
{
std::cout << "MyException caught" << std::endl;
// what() 是异常类提供的一个公共方法,它已被所有子异常类重载
std::cout << e.what() << std::endl;
}
catch(std::exception& e)
{
//其他的exception及其子类
}
catch(...)
{
//其他的exception
}
}
3. 动态内存
C++ 程序中的内存分为两个部分:
栈:在函数内部声明的所有变量都将占用栈内存。
堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
int main() {
int *ptr = NULL;
// 分配内存
ptr = new int;
// 判断内存是否分配成功
if (!ptr) {
exit(-1);
}
*ptr = 12;
// 释放内存
delete ptr;
return 0;
}
// 一维数组
// 动态分配,数组长度为 m
int *array=new int [m];
//释放内存
delete [] array;
// 二维数组
int **array;
// 假定数组第一维长度为 m, 第二维长度为 n
int m = 3, n = 5;
// 动态分配空间
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;
// 为对象分配内存空间
class Box
{
int width;
int height;
public:
void setWidth(int w);
void setHeight(int h);
int getArea();
};
Box* box = new Box;
box->setWidth(2);
box->setHeight(3);
std::cout << "box area: " << box->getArea() << std::endl;
delete box;
4. 命名空间
#include <iostream>
using namespace std;
// 命名空间的定义,使用关键字 namespace
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
}
int main ()
{
// 调用命名空间中的函数/变量
first_space::func();
return 0;
}
==>
// using namespace xxx
using namespace first_space;
int main ()
{
// 使用了using, first_space::func();
func();
return 0;
}
5. 模板
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector 或 vector 。
函数模板
// 模板函数定义的一般形式
template <typename type> ret-type func-name(parameter list)
{
// 函数的主体
}
// 示例
template <typename T>
inline T const& Max (T const& a, T const& b)
{
return a < b ? b:a;
}
类模板
template <class type> class class-name {
// xxxxx
}
// 示例
template <class T>
class Stack {
private:
vector<T> elems; // 元素
public:
void push(T const&); // 入栈
void pop(); // 出栈
T top() const; // 返回栈顶元素
bool empty() const{ // 如果为空则返回真。
return elems.empty();
}
};
// Stack::push的实现
template <class T>
void Stack<T>::push (T const& elem)
{
// 追加传入元素的副本
elems.push_back(elem);
}
int main()
{
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈
// 操作 int 类型的栈
intStack.push(7);
}
catch (exception const& ex) {
cerr << "Exception: " << ex.what() <<endl;
return -1;
}
}
6. 预处理器
C++ 还支持很多预处理指令,比如 #include、#define、#if、#else、#line 等。
#define PI 3.14159
cout << "Value of PI :" << PI << endl;
#define MIN(a,b) (a<b ? a : b)
cout <<"较小的值为:" << MIN(i, j) << endl;
#define DEBUG
// 条件编译
#ifdef DEBUG
cerr <<"Variable x = " << x << endl;
#endif
#if 0
不进行编译的代码
#endif
// # 运算符会把替换的令牌转换为用引号引起来的字符串,即"x"
#define MKSTR( x ) #x
// ## 运算符用于连接两个令牌,即xy
#define CONCAT( x, y ) x ## y
C++ 中的预定义宏
宏 | 描述 |
---|---|
__LINE__ | 这会在程序编译时包含当前行号。 |
__FILE__ | 这会在程序编译时包含当前文件名。 |
__DATE__ | 这会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。 |
__TIME__ | 这会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。 |
7. 信号处理
信号是由操作系统传给进程的中断,会提早终止一个程序。
有些信号不能被程序捕获,但是下表所列信号可以在程序中捕获,并可以基于信号采取适当的动作。这些信号是定义在 C++ 头文件 中。
信号 | 描述 |
---|---|
SIGABRT | 程序的异常终止,如调用 abort。 |
SIGFPE | 错误的算术运算,比如除以零或导致溢出的操作。 |
SIGILL | 检测非法指令。 |
SIGINT | 程序终止(interrupt)信号。 |
SIGSEGV | 非法访问内存。 |
SIGTERM | 发送到程序的终止请求。 |
注册信号:signal() 函数
void (*signal (int sig, void (*func)(int)))(int);
生成信号:raise() 函数
int raise (signal sig);
#include <iostream>
#include <csignal>
#include <unistd.h>
using namespace std;
void signalHandler( int signum )
{
cout << "Interrupt signal (" << signum << ") received.\n";
// 清理并关闭
// 终止程序
exit(signum);
}
int main ()
{
// 注册信号 SIGINT 和信号处理函数signalHandler
signal(SIGINT, signalHandler);
while(1){
cout << "Going to sleep...." << endl;
if( i == 3 ){
// 生成信号
raise( SIGINT);
}
sleep(1);
}
return 0;
}
8. 多线程
https://www.runoob.com/cplusplus/cpp-multithreading.html
9. Web 编程
https://www.runoob.com/cplusplus/cpp-web-programming.html
标准模板库(STL)
1. STL 教程
https://www.runoob.com/cplusplus/cpp-stl-tutorial.html
2. 标准库
https://www.runoob.com/cplusplus/cpp-standard-library.html
3. 有用的资源
C++ 有用的网站
C++ Standard Library headers − C++ 标准库。
C++ Programming − 这本书涵盖了 C++ 语言编程、软件交互设计、C++ 语言的现实生活应用。
C++ FAQ − C++ 常见问题
Free Country − Free Country 提供了免费的 C++ 源代码和 C++ 库,这些源代码和库涵盖了压缩、存档、游戏编程、标准模板库和 GUI 编程等 C++ 编程领域。
C and C++ Users Group − C 和 C++ 的用户团体提供了免费的涵盖各种编程领域 C++ 项目的源代码,包括 AI、动画、编译器、数据库、调试、加密、游戏、图形、GUI、语言工具、系统编程等。
C++ 有用的书籍
《Essential C++ 中文版》
《C++ Primer Plus 第6版中文版》
《C++ Primer中文版(第5版)》
4. 实例
https://www.runoob.com/cplusplus/cpp-examples.html
参考:
菜鸟教程-C++教程