C++ 快速入门笔记:进阶编程
C++入门笔记:高级编程
文件和流
打开文件
void open (const char *filename, ios::openmode mode);
- ios::app 追加模式。所有写入都追加到文件末尾
- ios::ate 文件打开后定位到文件末尾
- ios::in 打开文件用于读取
- ios::out 打开文件用于写入
- ios::trunc 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。
关闭文件
void close();
写入文件
- 使用流插入运算符 ( << ),向 ofstream / fstream 流中写入信息
读取文件
- 使用流提取运算符 ( >> ),向 ifstream / fstream 流中写入信息
文件读写实例
#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;
}
文件位置指针
stream 和 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 );
异常处理
try / catch / throw
- try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
- catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
- throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
C++ 标准的异常
异常 描述 std::exception 该异常是所有标准 C++ 异常的父类。 std::bad_alloc 该异常可以通过 new 抛出。 std::bad_cast 该异常可以通过 dynamic_cast 抛出。 std::bad_exception 这在处理 C++ 程序中无法预期的异常时非常有用。 std::bad_typeid 该异常可以通过 typeid 抛出。 std::logic_error 理论上可以通过读取代码来检测到的异常。 std::domain_error 当使用了一个无效的数学域时,会抛出该异常。 std::invalid_argument 当使用了无效的参数时,会抛出该异常。 std::length_error 当创建了太长的 std::string 时,会抛出该异常。 std::out_of_range 该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator。 std::runtime_error 理论上不可以通过读取代码来检测到的异常。 std::overflow_error 当发生数学上溢时,会抛出该异常。 std::range_error 当尝试存储超出范围的值时,会抛出该异常。 std::underflow_error 当发生数学下溢时,会抛出该异常。 定义新的异常
- 通过继承或重载 exception 类来定义新的异常
#include <iostream>
#include <exception>
using namespace std; struct MyException : public exception
{
const char * what () const throw ()
{
return "C++ Exception";
}
}; int main()
{
try
{
throw MyException();
}
catch(MyException& e)
{
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
}
catch(std::exception& e)
{
//其他的错误
}
}
- 通过继承或重载 exception 类来定义新的异常
动态内存
C++ 程序中的内存分为两个部分
- 栈:在函数内部声明的所有变量都将占用栈内存。
- 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
可以使用 new 运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。
不需要动态分配内存时,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。
new 和 delete 运算符
使用 new 运算符来为任意的数据类型动态分配内存
// new data-type;
// 如果自由存储区已被用完,可能无法成功分配内存。所以建议检查 new 运算符是否返回 NULL 指针。
double* pvalue = NULL;
if( !(pvalue = new double ))
{
cout << "Error: out of memory." <<endl;
exit(1); }
使用 delete 操作符释放它所占用的内存
#include <iostream>
using namespace std; int main ()
{
double* pvalue = NULL; // 初始化为 null 的指针
pvalue = new double; // 为变量请求内存
*pvalue = 29494.99; // 在分配的地址存储值
cout << "Value of pvalue : " << *pvalue << endl;
delete pvalue; // 释放内存
return 0;
}
数组的动态内存分配
int ROW = 2;
int COL = 3;
double **pvalue = new double* [ROW]; // 为行分配内存 // 为列分配内存
for(int i = 0; i < COL; i++) {
pvalue[i] = new double[COL];
}
for(int i = 0; i < COL; i++) {
delete[] pvalue[i];
}
delete [] pvalue;
对象的动态内存分配
#include <iostream>
using namespace std; class Box
{
public:
Box() {
cout << "调用构造函数!" <<endl;
}
~Box() {
cout << "调用析构函数!" <<endl;
}
}; int main( )
{
Box* myBoxArray = new Box[4];
delete [] myBoxArray; // Delete array
return 0;
}
命名空间
命名空间可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。
定义命名空间
#include <iostream>
using namespace std; // 第一个命名空间
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
}
// 第二个命名空间
namespace second_space{
void func(){
cout << "Inside second_space" << endl;
}
}
int main ()
{<span class="hljs-comment">// 调用第一个命名空间中的函数</span>
first_space::func(); <span class="hljs-comment">// 调用第二个命名空间中的函数</span>
second_space::func(); <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
```
using 指令
#include <iostream>
using namespace std; // 第一个命名空间
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
}
// 第二个命名空间
namespace second_space{
void func(){
cout << "Inside second_space" << endl;
}
}
using namespace first_space;
int main ()
{<span class="hljs-comment">// 调用第一个命名空间中的函数</span>
func(); <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
#include <iostream>
using std::cout; int main ()
{
cout << "std::endl is used with std!" << std::endl; return 0;
}
不连续的命名空间
- 命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。
嵌套的命名空间
#include <iostream>
using namespace std; // 第一个命名空间
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
// 第二个命名空间
namespace second_space{
void func(){
cout << "Inside second_space" << endl;
}
}
}
using namespace first_space::second_space;
int main ()
{
// 调用第二个命名空间中的函数
func();
return 0;
}
模板
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector <int> 或 vector <string>。
函数模板
template <class type> ret-type func-name(parameter list)
{
// 函数的主体
}
- 在这里,type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。
#include <iostream>
#include <string> using namespace std; template <typename T>
inline T const& Max (T const& a, T const& b)
{
return a < b ? b:a;
}
int main ()
{<span class="hljs-keyword">int</span> i = <span class="hljs-number">39</span>;
<span class="hljs-keyword">int</span> j = <span class="hljs-number">20</span>;
<span class="hljs-built_in">cout</span> << <span class="hljs-string">"Max(i, j): "</span> << Max(i, j) << <span class="hljs-built_in">endl</span>; <span class="hljs-keyword">double</span> f1 = <span class="hljs-number">13.5</span>;
<span class="hljs-keyword">double</span> f2 = <span class="hljs-number">20.7</span>;
<span class="hljs-built_in">cout</span> << <span class="hljs-string">"Max(f1, f2): "</span> << Max(f1, f2) << <span class="hljs-built_in">endl</span>; <span class="hljs-built_in">string</span> s1 = <span class="hljs-string">"Hello"</span>;
<span class="hljs-built_in">string</span> s2 = <span class="hljs-string">"World"</span>;
<span class="hljs-built_in">cout</span> << <span class="hljs-string">"Max(s1, s2): "</span> << Max(s1, s2) << <span class="hljs-built_in">endl</span>; <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
类模板
template <class type> class class-name { }
- 在这里,type 是占位符类型名称,可以在类被实例化的时候进行指定。您可以使用一个逗号分隔的列表来定义多个泛型数据类型。
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept> using namespace std; template <class T>
class Stack {
private:
vector<T> elems; // 元素<span class="hljs-keyword">public</span>:
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">push</span><span class="hljs-params">(T <span class="hljs-keyword">const</span>&)</span></span>; <span class="hljs-comment">// 入栈</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">pop</span><span class="hljs-params">()</span></span>; <span class="hljs-comment">// 出栈</span>
<span class="hljs-function">T <span class="hljs-title">top</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span></span>; <span class="hljs-comment">// 返回栈顶元素</span>
<span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">empty</span><span class="hljs-params">()</span> <span class="hljs-keyword">const</span></span>{ <span class="hljs-comment">// 如果为空则返回真。</span>
<span class="hljs-keyword">return</span> elems.empty();
}
};
template <class T>
void Stack<T>::push (T const& elem)
{
// 追加传入元素的副本
elems.push_back(elem);
}template <class T>
void Stack<T>::pop ()
{
if (elems.empty()) {
throw out_of_range("Stack<>::pop(): empty stack");
}
// 删除最后一个元素
elems.pop_back();
}template <class T>
T Stack<T>::top () const
{
if (elems.empty()) {
throw out_of_range("Stack<>::top(): empty stack");
}
// 返回最后一个元素的副本
return elems.back();
}int main()
{
try {
Stack<int> intStack; // int 类型的栈
Stack<string> stringStack; // string 类型的栈<span class="hljs-comment">// 操作 int 类型的栈 </span>
intStack.push(<span class="hljs-number">7</span>);
<span class="hljs-built_in">cout</span> << intStack.top() <<<span class="hljs-built_in">endl</span>; <span class="hljs-comment">// 操作 string 类型的栈 </span>
stringStack.push(<span class="hljs-string">"hello"</span>);
<span class="hljs-built_in">cout</span> << stringStack.top() << <span class="hljs-built_in">std</span>::<span class="hljs-built_in">endl</span>;
stringStack.pop();
stringStack.pop();
}
<span class="hljs-keyword">catch</span> (exception <span class="hljs-keyword">const</span>& ex) {
<span class="hljs-built_in">cerr</span> << <span class="hljs-string">"Exception: "</span> << ex.what() <<<span class="hljs-built_in">endl</span>;
<span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
}
}
预处理器
#define 预处理
define 预处理指令用于创建符号常量。该符号常量通常称为宏。
#define macro-name replacement-text
函数宏
使用 #define 来定义一个带有参数的宏:
#define MIN(a,b) (((a)<(b)) ? a : b)
条件编译
有几个指令可以用来有选择地对部分程序源代码进行编译。这个过程被称为条件编译。
ifdef & endif
#ifndef NULL
#define NULL 0
#endif
DEBUG 模式
#ifdef DEBUG
cerr <<"Variable x = " << x << endl;
#endif
可以使用 #if 0 语句注释掉程序的一部分。
#if 0
不进行编译的代码
#endif
# 和 ## 运算符
运算符会把 replacement-text 令牌转换为用引号引起来的字符串。
#include <iostream>
using namespace std;
#define MKSTR( x ) #x int main ()
{
cout << MKSTR(HELLO C++) << endl;
return 0;
}
运算符用于连接两个令牌。
#include <iostream>
using namespace std;
#define concat(a, b) a ## b
int main()
{
int xy = 100;
cout << concat(x, y);
return 0;
}
预定义宏
宏 描述 _LINE_ 这会在程序编译时包含当前行号。 _FILE_ 这会在程序编译时包含当前文件名。 _DATE_ 这会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。 _TIME_ 这会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。
信号处理
信号是由操作系统传给进程的中断,会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上,可以通过按 Ctrl+C 产生中断。
可捕获的信号表(定义在 <csignal> 中)
信号 描述 SIGABRT 程序的异常终止,如调用 abort。 SIGFPE 错误的算术运算,比如除以零或导致溢出的操作。 SIGILL 检测非法指令。 SIGINT 接收到交互注意信号。 SIGSEGV 非法访问内存。 SIGTERM 发送到程序的终止请求。 signal() 函数
用来捕获突发事件
void (*signal (int sig, void (*func)(int))(int);
接收两个参数:第一个参数是一个整数,代表信号编号;第二个参数是一个指向信号处理函数的指针。
无论要在程序中捕获什么信号,都必须使用 singal 函数来注册信号,并将其与信号处理程序相关联。
#include <iostream>
#include <csignal>
using namespace std;
void signalHandler( int signum )
{
cout << "Interrupt signal (" << signum << ") received.\n";
// 清理并关闭
// 终止程序
exit(signum);
} int main ()
{
// 注册信号 SIGINT 和信号处理程序
signal(SIGINT, signalHandler);
while(1){
cout << "Going to sleep...." << endl;
sleep(1);
}
return 0;
}
raise() 函数
使用函数 raise() 生成信号。
int raise (signal sig);
sig 是要发送的信号编号,这些信号包括:SIGINT SIGABRT SIGFPE SIGILL SIGSEGV SIGTERM SIGHUP
#include <iostream>
#include <csignal>
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;
}
</div>
C++ 快速入门笔记:进阶编程的更多相关文章
- [Java入门笔记] 面向对象编程基础(二):方法详解
什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...
- webpack快速入门——CSS进阶:自动处理CSS3前缀
为了浏览器的兼容性,有时候我们必须加入-webkit,-ms,-o,-moz这些前缀.目的就是让我们写的页面在每个浏览器中都可以顺利运行. 1.安装 cnpm i postcss-loader aut ...
- webpack快速入门——CSS进阶,Less文件的打包和分离
1.要使用less,首先使用npm安装less服务 cnpm install less --save-dev 还需要安装Less-loader用来打包使用. cnpm install less-loa ...
- webpack快速入门——CSS进阶:SASS文件的打包和分离
1.安裝:因为sass-loader依赖于node-sass,所以需要先安装node-sass cnpm install node-sass --save-dev cnpm install sass- ...
- webpack快速入门——CSS进阶:消除未使用的CSS
使用PurifyCSS可以大大减少CSS冗余 1.安装 cnpm i purifycss-webpack purify-css --save-dev 2.引入glob,因为我们需要同步检查html模板 ...
- C#快速入门笔记(1)——基础语法
C#快速入门笔记(1)——基础语法 总体框架:
- python快速入门及进阶
python快速入门及进阶 by 小强
- keras搭建神经网络快速入门笔记
之前学习了tensorflow2.0的小伙伴可能会遇到一些问题,就是在读论文中的代码和一些实战项目往往使用keras+tensorflow1.0搭建, 所以本次和大家一起分享keras如何搭建神经网络 ...
- 【干货合集】Docker快速入门与进阶
收录待用,修改转载已取得腾讯云授权 Docker 在众多技术中,绝对是当红炸子鸡.这年头,如果你不懂一点容器,不学一些Docker,还怎么出去跟人炫耀技术? Docker 也是云计算技术中较为热门的一 ...
随机推荐
- 7.3 GROUP BY的“新”功能
7.3 GROUP BY的"新"功能正在更新内容,请稍后
- Log4j.properties 属性详解以及 LOG4J日志级别详解
转自:https://blog.csdn.net/lovely0903jpp/article/details/82261607 假如项目的生产环境上增加请求以及响应信息的打印,这个时候,对于新手来说, ...
- .NET中StringBuilder用法实例分析
string s1 = "33"; string s2 = "44"; string s3 = "55"; //需求是把s1 s2 s3拼接 ...
- rhel5安装 oracle10
readhat 安装11gr2文档 需要注意的地方:必须关掉的 1,防火墙:2,SElinux . root 用户运行 setup 命令可关防火墙与SElinux 修改网络配置文件,一定要重启此文 ...
- js常用数据转换&判断
数组转字符串 var a, b; a = new Array(0,1,2,3,4); b = a.join("-"); //"0-1-2-3-4" 字符串转数组 ...
- python文件的操作
文件的操作,归根结底就只有两种:打开文件.操作文件 一.打开文件:文件句柄 = open('文件路径', '模式') python中打开文件有两种方式,即:open(...) 和 file(...) ...
- 【Codeforces Round #432 (Div. 2) B】Arpa and an exam about geometry
[链接]h在这里写链接 [题意] 给你3个点A,B,C 问你能不能将纸绕着坐标轴上的一点旋转.使得A与B重合,B与C重合 [题解] 这3个点必须共圆. 则A,B,C不能为一条直线.否则无解. 共圆之后 ...
- datagridview问题
在winform中,取datagridview某个单元格的值,然后与另外一个值相减,如果相减等于0,结果却为-7.105427357601E-15 Convert.ToDouble(xun_dataG ...
- 下拉列表,点击选择实现跳转链接 onchange="window.location=..."
<select onchange="window.location=this.value;"> <option value="a.html"& ...
- Centos minimal 安装桌面
yum update yum groupinstall -y 'X Window System' yum groupinstall -y 'Desktop' #中文支持 yum groupinstal ...