IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++总复习 -> 正文阅读

[C++知识库]c++总复习

最后更新于 2021-11-18 at 22:10:23 CST

1 绪论

  1. 什么是面向对象的方法?

    首先,它将数据及对数据的操作方法放在一起,作为一个互相依存、不可分离的整体——对象。

    对同类型对象抽象出其共性,形成类。

    类中的大多数数据,只能通过本类的方法进行处理。

    类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信

  2. 面向对象的基本概念

    • 对象

      面向对象方法中的对象,是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位。

      对象由一组属性和一组行为构成

    • 面向对象中的“类”,是具有相同属性和服务的一组对象的集合。

    • 封装

      封装是面向对象的一个重要原则,就是把对象的属性和服务结合成一个独立的系统单位,并尽可能隐藏对象的内部细节。

    • 继承

      特殊的类的对象拥有其一般类的全部属性和服务,称作特殊类的对一般类的继承。

    • 多态性

      多态性是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。

  3. C++两个主要特点——[ 尽量兼容C,支持面向对象的方法 ]

  4. 面向对象程序设计的基本特点

    • 抽象

      面向对象方法中的抽象,是指对具体问题(对象)进行概括,抽出一类的对象的公共性质并加以描述的过程

    • 封装

      封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的函数代码进行有机的结合,形成“类”,其中的数据和函数都是类的成员。

    • 继承

      C++中提供了类的继承机制,允许程序员在保持原有类特性的基础上,进行更具体、更详细的说明。

    • 多态

      多态是指一段程序能够处理多种类型对象的能力。在C++语言中,这种多态性可以通过强制多态、重载多态、类型参数化多态、包含多态4种形式来实现。

  5. 对象和类的联系

    类是对象的抽象;对象是类的一个特定实例

2 参数传递

  1. 值传递不影响实参,引用传递和指针传递可以影响实参

  2. 值(val)传递

    #include <iostream>
    using namespace std;
    
    /*val*/
    void swap(int i,int j){
        int temp;
        temp = i;
        i = j;
        j = temp;
        cout<<"swap in the function: "<<
            "i="<<i<<" j="<<j<<endl;
    }
    
    int main(){
        int a,b;
        a = 1;
        b = 2;
        swap(a,b);
        cout<<"out the function: "<<
            "a="<<a<<" b="<<b<<endl;
    }
    
    /*
     * swap in the function: i=2 j=1
     * out the function: a=1 b=2
     */
    
  3. 引用(reference)传递

    #include <iostream>
    using namespace std;
    
    /*reference*/
    void swap(int &i,int &j){
        int temp;
        temp = i;
        i = j;
        j = temp;
        cout<<"swap in the function: "<<
        "i="<<i<<" j="<<j<<endl;
    }
    
    int main(){
        int a,b;
        a = 1;
        b = 2;
        swap(a,b);
        cout<<"out the function: "<<
            "a="<<a<<" b="<<b<<endl;
    }
    
    /*
     * swap in the function: i=2 j=1
     * out the function: a=2 b=1
     * */
    
  4. 指针(pointer)传递

    #include <iostream>
    using namespace std;
    
    /*pointer*/
    void swap(int *i,int *j){
        int temp;
        temp = *i;
        *i = *j;
        *j = temp;
        cout<<"swap in the function: "<<
        "i="<<*i<<" j="<<*j<<endl;
    }
    
    int main(){
        int a,b;
        a = 1;
        b = 2;
        swap(&a,&b);
        cout<<"out the function: "<<
            "a="<<a<<" b="<<b<<endl;
    }
    
    /*
     * swap in the function: i=2 j=1
     * out the function: a=2 b=1
     * */
    

3 内联函数

  1. 为什么使用内联函数

    内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。

    如此,节省了参数传递、控制转移等开销。

  2. 使用内联函数的条件

    通常内联函数应该是比较简单的函数,结构简单,语句少。如果将一个复杂的函数定义为内联函数,反而会造成代码膨胀,增大开销。

  3. 将一个函数声明为内联函数——使用关键字inline

    inline [returnType] [functionName](args){
        [function body];
    }
    
  4. 实例——根据圆的半径求其面积

    #include <iostream>
    using namespace std;
    
    const double PI = 3.1415926;
    
    inline double getArea(double radius){
        return PI*radius*radius;
    }
    
    int main(){
        double radius = 2.5;
        double area = getArea(radius);
        cout<<area<<endl;
        return 0;
    }
    

4 带默认形参值的函数

  1. **函数在定义时可以预先声明默认的形参值。**调用时如果给出实参,则用实参来初始化形参,如果没有给出实参,则采用预先生命的默认形参值。例如

    #include <iostream>
    using namespace std;
    
    inline double getGravity
    (double weight,double gravition_acceleration=9.80665);
    
    int main(){
        double m0 = 10.0;
        cout<<"m0="<<m0<<endl;
        cout<<"gravition_acceleration=9.80665 -> "<<getGravity(10.0)<<endl;
        cout<<"gravition_acceleration=10.0000 -> "<<getGravity(10.0,10.0)<<endl;
    }
    
    inline double getGravity
    (double weight,double gravition_acceleration)
    {
        return weight*gravition_acceleration;
    }
    
    /*
     * m0=10
     * gravition_acceleration=9.80665 -> 98.0665
     * gravition_acceleration=10.0000 -> 100
     * */
    
  2. 两个注意事项

    • 在相同的作用域内,不允许在同一个函数的多个声明中对同一个参数的默认值重复定义,即使前后定义的值相同也不行。

    • 反过来,若作用域不同,前后定义的默认值不同是允许的。

      例子,在类内和类外定义带默认参数的函数

      #include <iostream>
      using namespace std;
      
      inline int fun(int i=0){
          return i;
      }
      
      class Samp1e {
      public:
          inline int fun(int j=1){
              return j;
          }
      private:
          int var;
      };
      
      Samp1e s;
      
      int main(){
          cout<<"member function return: "<<s.fun()<<endl;
          cout<<"function out of the class return: "<<fun()<<endl;
      
      }
      
      /*
       * member function return: 1
       * function out of the class return: 0
       * */
      

5 函数的重载

  1. 概念

    两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载。

  2. 例子:

    #include <iostream>
    using namespace std;
    
    int additionOfSquare(int i,int j){
        cout<<"int"<<endl;
        return i*i+j*j;
    }
    
    double additionOfSquare(double i,double j){
        cout<<"double"<<endl;
        return i*i+j*j;
    }
    
    int main(){
        double r = 2.71828, s = 3.1415926;
        cout<<additionOfSquare(r,s)<<endl;
        int u = (int) r,v = (int) s;
        cout<<additionOfSquare(u,v)<<endl;
    }
    
    /*
     * double
     * 17.2587
     * int
     * 13
     */
    
  3. 注意

    当使用带有默认形参值的函数重载形式时,需要注意防止二义性。例如下面的两个函数原型,在编译时无法区别为不同的重载形式。

    void fun(int length,int width=2,int height = 3);
    void fun(int length);
    

    再如

    int additionOfSquare(int i,int j){
        cout<<"int"<<endl;
        return i*i+j*j;
    }
    
    double additionOfSquare(double i,double j){
        cout<<"double"<<endl;
        return i*i+j*j;
    }
    

    调用

    int main(){
        double r = 2.71828;
        int u = (int) r;
        additionOfSquare(r,u);
    }
    

    也会产生歧义。

6 类和对象

  1. 序言

    • 类是面向对象程序设计方法的核心,利用类可以实现对数据的封装和隐蔽

    • 在面向对象程序设计中,程序模块是由类构成的。类是对逻辑上相关的函数与数据的封装,它是对问题的抽象描述

  2. 类的定义

    class [className]{
    public:
        [external interface];
    protected:
        [protected members];
    private:
        [private members];
    };
    
  3. 类成员的访问控制

派生对象外部友元
public
privateXX
protectedX
  1. 对象

    略;

  2. 成员函数

    • 成员函数的定义

      returnType className::functionName(args...){
          function body;
      }
      

      在类内定义成员函数时,可以不指明该函数属于哪个类

      returnType functionName(args.){
          function body;
      }
      
    • 成员函数的调用

      class A{
      public:
          void fun();
      }
      void A::fun(){
          cout<<"A"<<endl;
      };
      

      调用的两种方式:

      • 点运算符( . )
      A a;
      a.fun();
      
      • 箭头运算符( -> )
      A *pa = new A;
      pa->fun();
      delete pa;
      
    • 成员函数调用中的目的对象

      调用一个成员函数与调用普通函数的差异在于需要使用点运算符(".")指出调用所针对的对象,这一对象在本次调用中称为目的对象。

      例如使用 a.fun() 调用fun()成员函数时,a 就是这一调用过程中的目的对象。

    • 带默认形参值的成员函数

      和普通函数相差无几,略;

    • 内联成员函数

      略;

7 构造函数和析构函数

  1. 总概

    在定义对象的时候进行的数据成员设置,称为对象的初始化。在特定对象使用结束时,还经常需要进行一些清理工作。C++程序中的初始化和清理工作,分别由两个特殊的成员函数来完成,他们就是构造函数和析构函数。

  2. 构造函数(Constructor)

    • **作用:**构造函数的作用就是在对象被创建时利用特定的的值构造对象,将对象初始化为一个特定的状态。

    • 一些特殊的性质

      • 构造函数的函数名与类名相同,而且没有返回值;
      • 构造函数通常被声明为公有函数
      • 构造函数在对象被创建时将被自动调用
    • 定义

      class className{
      public:
          className(arg1,arg2,args3,...):var1(arg1),var2(arg2),var3(arg3){
              [function body];
          }
      private:
          [members];
      }
      

      如上代码中,var0,var1,var2…代表类中的数据成员,而 var1(arg1) 表示用用构造函数的形参 arg1 来给数据成员 var1初始化(赋初值)。

    • 例,

      虚数类的构造函数

      class imaginary_number{
      public:
          imaginary_number(double real, double imaginary)
          : real(real), imaginary(imaginary)
          {
              cout<<"cons."<<endl;
          }
      private:
          double real;
          double imaginary;
      };
      
    • 复制构造函数

      复制构造函数是一种特殊的构造函数,其形参是本类的对象的引用。其作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。

      若没有定义类的复制构造函数,系统会在必要时生成一个隐含的复制构造函数,其功能为:把初始值对象的每个数据成员的值复制到新建立的对象中。

    • 复制构造函数,例

      #include <iostream>
      using namespace std;
      
      
      class imaginary_number{
      public:
          imaginary_number(double real, double imaginary)
          : real(real), imaginary(imaginary)
          {
              cout<<"cons."<<endl;
          }
          imaginary_number(const imaginary_number &imaginaryNumber){
              this->real = imaginaryNumber.real;
              this->imaginary = imaginaryNumber.imaginary;
              cout<<"copied."<<endl;
          }
      
          friend std::ostream &operator<<(std::ostream &os, const imaginary_number &number) {
              os <<number.real <<"+"<< number.imaginary<<"i";
              return os;
          }
      
      private:
          double real;
          double imaginary;
      };
      
      int main(){
          imaginary_number in1(1,2);
          cout<<"origin: "<<in1<<endl;
          imaginary_number *pn = new imaginary_number(in1);
          cout<<"copy: "<<*pn<<endl;
          delete pn;
          return 0;
      }
      
      /*
       * cons.
       * origin: 1+2i
       * copied
       * copy: 1+2i
       * */
      
    • 构造函数允许重载 Override

      复制构造函数和普通构造函数互为重载函数。

      在工程中,类中要有无参构造和有参构造,

      无参构造和有参构造互为重载函数,

      如下学生(Stu)类

      #include <iostream>
      using namespace std;
      
      
      class Stu{
      private:
      public:
          /*有参构造*/
          Stu(const string &name, const string &stuNum, double gpa) :
          name(name), stuNum(stuNum), gpa(gpa) {
              cout<<"stu cons."<<endl;
          }
      
          /*无参构造*/
          Stu() {
              cout<<"stu cons without initial value"<<endl;
          }
      
          void setName(const string &name) {
              Stu::name = name;
          }
      
          void setStuNum(const string &stuNum) {
              Stu::stuNum = stuNum;
          }
      
          void setGpa(double gpa) {
              Stu::gpa = gpa;
          }
      
      private:
          string name;
          string stuNum;
          double gpa;
      };
      
      int main(){
          Stu *pss[3];
          for(int i=0;i<3;i++){
              /*调用无参构造函数*/
              pss[i] = new Stu;
          }
          /*调用有参构造函数*/
          Stu s("ken","201",3.9);
          for(int j=0;j<3;j++){
              delete pss[j];
          }
      }
      
      
      /*
       * stu cons without initial value
       * stu cons without initial value
       * stu cons without initial value
       * stu cons.
       */
      
  3. 析构函数(Destructor)

    • 作用

      构函数与构造函数的作用几乎正好相反,它用来完成对象被删除前的一些清理工作。

    • 一些性质

      • 构函数是在对象的生存周期即将结束的时刻被自动调用的。
      • 与构造函数一样,析构函数通常也是类的一个公有函数成员,它的名称是由类名前面加“~”构成,没有返回值;但与构造函数不同的是,析构函数不接受任何参数,不支持重载
      • 如果不进行显式说明,系统会自动生成一个函数体为空的析构函数。
    • 例子,类 Apple,其中的静态数据成员 apple_count 用来计数苹果的数量。

      #include <iostream>
      
      using namespace std;
      
      class Apple{
      public:
          Apple(const string &kind) : kind(kind) {
              apple_count++;
              cout<<"apple "<<kind<<" cons."<<endl;
          }
          Apple(){
      
          }
      
          ~Apple(){
              apple_count--;
              cout<<"apple "<<kind<<" des."<<endl;
          }
      
          static int getAppleCount();
      
      private:
          static int apple_count;
          string kind;
      };
      int Apple::apple_count = 0;
      
      int Apple::getAppleCount() {
          return apple_count;
      }
      
      
      int main(){
          Apple *pa1 = new Apple("花牛");
          Apple *pa2 = new Apple("蛇果");
          cout<<"有"<<pa2->getAppleCount()<<"种苹果"<<endl;
          delete pa1;
          cout<<"有"<<pa2->getAppleCount()<<"种苹果"<<endl;
          delete pa2;
      }
      
      /*
       * apple 花牛 cons.
       * apple 蛇果 cons.
       * 有2种苹果
       * apple 花牛 des.
       * 有1种苹果
       * apple 蛇果 des.
       * */
      
    • 系统何时调用析构函数?

      class Samp1e{
      public:
          ~Samp1e(){
              cout<<"des."<<endl;
          }
      };
      
      • 对象生命周期结束,被销毁时;

        int main(){
            Samp1e s;
        }
        

        类Samp1e的对象 s 在 main 函数中是形参

        形参的生命周期和所在函数的生命周期相同。因而main函数运行结束后,对象 s 自动销毁,调用析构函数。

        这种情况还可能发生在 [对象作为函数形参对象直接作为函数返回值(对象引用或者指向对象的指针作为返回值不调用析构函数)]这两种情况中,因为在上述两种情况中,系统会生成该对象的副本,当副本的生命周期结束时,调用析构函数。

        #include <iostream>
        
        using namespace std;
        
        class Samp1e{
        public:
            ~Samp1e(){
                cout<<"Samp1e des."<<endl;
            }
        };
        
        inline void fun(Samp1e s1){
            return;
        }
        
        
        int main(){
            Samp1e *ps = new Samp1e;
            cout<<"对象作为函数参数:";
            fun(*ps);
            cout<<"[delete]指向对象指针:";
            delete ps;
        }
        
        /*
         * 对象作为函数参数:Samp1e des.
         * [delete]指向对象指针:Samp1e des.
         * */
        
        Samp1e *ps = new Samp1e;
        
        inline Samp1e fun(){
            return *ps;
        }
        
        int main(){
            cout<<"对象作为函数返回值:";
            fun();
            cout<<"[delete]指向对象指针:";
            delete ps;
        }
        
        /*
         * 对象作为函数返回值:Samp1e des.
         * [delete]指向对象指针:Samp1e des.
         * */
        
      • delete指向对象的指针时;

        int main(){
            Samp1e *ps = new Samp1e;
            delete ps;
        }
        
      • 对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用。

        #include <iostream>
        
        using namespace std;
        
        class Samp1e{
        public:
            ~Samp1e(){
                cout<<"Samp1e des."<<endl;
            }
        };
        
        class Samp2e{
        public:
            ~Samp2e(){
                cout<<"Samp2e des."<<endl;
            }
        
        private:
            Samp1e s1;
        };
        
        int main(){
            Samp2e s2;
        }
        
        /*
         * Samp2e des.
         * Samp1e des.
         * */
        
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-19 17:27:06  更:2021-11-19 17:28:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:33:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码