C++入门笔记:高级编程

文件和流

  1. 打开文件

    void open (const char *filename, ios::openmode mode);
    • ios::app 追加模式。所有写入都追加到文件末尾
    • ios::ate 文件打开后定位到文件末尾
    • ios::in 打开文件用于读取
    • ios::out 打开文件用于写入
    • ios::trunc 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。
  2. 关闭文件

    void close();
  3. 写入文件

    • 使用流插入运算符 ( << ),向 ofstream / fstream 流中写入信息
  4. 读取文件

    • 使用流提取运算符 ( >> ),向 ifstream / fstream 流中写入信息
  5. 文件读写实例

    #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;
    }
  6. 文件位置指针

    • 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 );

异常处理

  1. try / catch / throw

    • try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
    • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
    • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  2. 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 当发生数学下溢时,会抛出该异常。
  3. 定义新的异常

    • 通过继承或重载 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)

      {

      //其他的错误

      }

      }

动态内存

  1. C++ 程序中的内存分为两个部分

    • 栈:在函数内部声明的所有变量都将占用栈内存。
    • 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
  2. 可以使用 new 运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。

  3. 不需要动态分配内存时,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。

  4. 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;

      }

  5. 数组的动态内存分配

    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;

  6. 对象的动态内存分配

    #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;

    }

命名空间

  1. 命名空间可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。

  2. 定义命名空间

    #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>;

}

```

  1. 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;
    }
  2. 不连续的命名空间

    • 命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。
  3. 嵌套的命名空间

    #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;

    }

模板

  1. 模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

  2. 模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector <int> 或 vector <string>。

  3. 函数模板

    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> &lt;&lt; <span class="hljs-string">"Max(i, j): "</span> &lt;&lt; Max(i, j) &lt;&lt; <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> &lt;&lt; <span class="hljs-string">"Max(f1, f2): "</span> &lt;&lt; Max(f1, f2) &lt;&lt; <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> &lt;&lt; <span class="hljs-string">"Max(s1, s2): "</span> &lt;&lt; Max(s1, s2) &lt;&lt; <span class="hljs-built_in">endl</span>; <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

    }

  4. 类模板

    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>&amp;)</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> &lt;&lt; intStack.top() &lt;&lt;<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> &lt;&lt; stringStack.top() &lt;&lt; <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>&amp; ex) {
    <span class="hljs-built_in">cerr</span> &lt;&lt; <span class="hljs-string">"Exception: "</span> &lt;&lt; ex.what() &lt;&lt;<span class="hljs-built_in">endl</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;
    }

    }

预处理器

  1. #define 预处理

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

      #define macro-name replacement-text
  2. 函数宏

    • 使用 #define 来定义一个带有参数的宏:

      #define MIN(a,b) (((a)<(b)) ? a : b)
  3. 条件编译

    • 有几个指令可以用来有选择地对部分程序源代码进行编译。这个过程被称为条件编译。

    • ifdef & endif

      #ifndef NULL
      #define NULL 0
      #endif
    • DEBUG 模式

      #ifdef DEBUG
      cerr <<"Variable x = " << x << endl;
      #endif
    • 可以使用 #if 0 语句注释掉程序的一部分。

      #if 0
      不进行编译的代码
      #endif
  4. # 和 ## 运算符

    • 运算符会把 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;
      }
  5. 预定义宏

    描述
    _LINE_ 这会在程序编译时包含当前行号。
    _FILE_ 这会在程序编译时包含当前文件名。
    _DATE_ 这会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。
    _TIME_ 这会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。

信号处理

  1. 信号是由操作系统传给进程的中断,会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上,可以通过按 Ctrl+C 产生中断。

  2. 可捕获的信号表(定义在 <csignal> 中)

    信号 描述
    SIGABRT 程序的异常终止,如调用 abort。
    SIGFPE 错误的算术运算,比如除以零或导致溢出的操作。
    SIGILL 检测非法指令。
    SIGINT 接收到交互注意信号。
    SIGSEGV 非法访问内存。
    SIGTERM 发送到程序的终止请求。
  3. 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;

      }

  4. 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++ 快速入门笔记:进阶编程的更多相关文章

  1. [Java入门笔记] 面向对象编程基础(二):方法详解

    什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...

  2. webpack快速入门——CSS进阶:自动处理CSS3前缀

    为了浏览器的兼容性,有时候我们必须加入-webkit,-ms,-o,-moz这些前缀.目的就是让我们写的页面在每个浏览器中都可以顺利运行. 1.安装 cnpm i postcss-loader aut ...

  3. webpack快速入门——CSS进阶,Less文件的打包和分离

    1.要使用less,首先使用npm安装less服务 cnpm install less --save-dev 还需要安装Less-loader用来打包使用. cnpm install less-loa ...

  4. webpack快速入门——CSS进阶:SASS文件的打包和分离

    1.安裝:因为sass-loader依赖于node-sass,所以需要先安装node-sass cnpm install node-sass --save-dev cnpm install sass- ...

  5. webpack快速入门——CSS进阶:消除未使用的CSS

    使用PurifyCSS可以大大减少CSS冗余 1.安装 cnpm i purifycss-webpack purify-css --save-dev 2.引入glob,因为我们需要同步检查html模板 ...

  6. C#快速入门笔记(1)——基础语法

    C#快速入门笔记(1)——基础语法 总体框架:

  7. python快速入门及进阶

    python快速入门及进阶 by 小强

  8. keras搭建神经网络快速入门笔记

    之前学习了tensorflow2.0的小伙伴可能会遇到一些问题,就是在读论文中的代码和一些实战项目往往使用keras+tensorflow1.0搭建, 所以本次和大家一起分享keras如何搭建神经网络 ...

  9. 【干货合集】Docker快速入门与进阶

    收录待用,修改转载已取得腾讯云授权 Docker 在众多技术中,绝对是当红炸子鸡.这年头,如果你不懂一点容器,不学一些Docker,还怎么出去跟人炫耀技术? Docker 也是云计算技术中较为热门的一 ...

随机推荐

  1. jQuery快速入门知识重点

    1.jquery中attr与prop的区别   attr:是通过setAttribute 和 getAttribute来设置的使用的是DOM属性节点   prop:是通过document.getEle ...

  2. 洛谷 P1599 结算日

    洛谷 P1599 结算日 题目描述 “不放债不借债”,贝西多么希望自己可以遵循这个忠告.她已经和她的N(1 <= N <= 100,000)个朋友有了债务关系,或者借债了,或者放债了.她的 ...

  3. 把java程序打包成.exe

    准备工作:将可执行的jar包跟资源跟第三方包都放到一个目录下. 能够将jre包也放入里面.这样在没有安装jre的情况下也能够执行. watermark/2/text/aHR0cDovL2Jsb2cuY ...

  4. 浅谈Normalize.css

    浅谈Normalize.css 一.总结 1.Normalize.css:它在默认的HTML元素样式上提供了跨浏览器的高度一致性,花了几百个小时来努力研究不同浏览器的默认样式的差异. 2.优于rese ...

  5. 关于http请求指定本地ip

    static void Main(string[] args) { //ssl证书验证问题(没有校验) ServicePointManager.ServerCertificateValidationC ...

  6. JS学习笔记 - fgm练习 2-5 - 函数传参 设置div样式

    练习地址:http://www.fgm.cc/learn/lesson2/05.html <script> window.onload = function(){ var oDiv = d ...

  7. JS错误记录 - 按左右箭头div移动、一串div跟着鼠标移动

    本次练习错误总结: 1. div跟着用户操作而移动,首先必须要绝对定位,否则无法移动. 2. if条件语句里面是双等号,不是单等号(赋值). 3. 坐标值没有Right,只能offsetLeft 加减 ...

  8. Flask项目之手机端租房网站的实战开发(一)

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 一丶项目介绍 产品:关于手机移动端的租房网站 角色:在这个产品中用户包括房东与房客 功能:房东可以在这个平台发布自己的房屋,房客可 ...

  9. [D3] Create DOM Elements with D3 v4

    Change is good, but creating from scratch is even better. This lesson shows you how to create DOM el ...

  10. Iceberg使用

    Iceberg是Mac下比較好用的pkg生成工具. 在files中选择你想要存放(自己文件的目录),生成pkg后目录就会存储在设置的那个目录下. 点击scripts选择pkg安装各个阶段所要运行脚本路 ...