课程:
C++数据类型:https://www.runoob.com/cplusplus/cpp-data-types.html
C++远征之离港篇:https://www.imooc.com/learn/381
C++远征之封装篇(上):https://www.imooc.com/learn/382
C++远征之封装篇(下):https://www.imooc.com/learn/405

目标

读懂源码,简单编写功能代码。

开发工具Clion:下载,安装,激活。File -> Settings -> Build,Execution,Deployment -> Toolchains -> MinGW,下载编译工具。
默认多文件项目模式:新建项目FIle -> new project 新建项目,加载cmake信息、IDE debug图标点亮。

添加单文件运行插件:
Clion单个C++源文件编译执行的配置方法Windows下CLion中文乱码最有效的解决方式
注意:Editor -> File Encodeings -> utf8+utf8+utf8 ,main第一行添加system("chcp 65001 > nul")。

1、数据基础

a.数组、字符串、指针、结构体

1、数组(纯粹相同类型元素)
- 一维数组:double balance[5] = {1000.0, 2.0, 3.4};;
- 多维数组:
    int a[3][4] = {  
     {0, 1, 2, 3} ,   /*  初始化索引号为 0 的行 */
     {4, 5, 6, 7} ,   /*  初始化索引号为 1 的行 */
     {8, 9, 10, 11}   /*  初始化索引号为 2 的行 */
    };
2、字符串
- 定长字符串
    char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; //或
    char greeting[] = "Hello";
- 常用函数
    strcpy( dst_str, src_str )              //覆盖到
    strcat( str1, str2 )                    //连接
    strlen( s1 )
    strcmp(s1, s2);
        //如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0
    strchr(s1, ch)
        //返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置:即返回之后的字符串是 s1[:xx]
    strstr(s1, s2)
        //同上,返回字符串余下所有(包含)
3、指针与引用(地址vs别名)
- 变量定义:
    int * p;                                  //指针:第一个数组元素、或区块的第一个字符的地址
    int ** pptr;
    int * p[10];
    int & q = a;                              //引用:变量别名、修改则拷贝新到副本
- 传递函数值、返回值
    double * getAverage(int *arr, int size);
    double * getAverage(int *arr, int size){}    
    void & swap(int & x, int & y);
    void & swap(int & x, int & y){}
4、时间标准库
- clock()
       start_t = clock();
       for(i=0; i< 10000000; i++) { }
       end_t = clock();
       total_t = (double)(end_t - start_t) / CLOCKS_PER_SEC;
5、结构体
- .点访问成员
- 定义
    struct Books
    {
       char  title[50];
       char  author[50];
       char  subject[100];
       int   book_id;
    };
    //定义结构类型、同时定义一个变量(空)
    struct Books
    {
       char  title[50];
       char  author[50];
       char  subject[100];
       int   book_id;
    } book;
- 结构类型的指针参数
    void printBook( struct Books * book );
    void printBook( struct Books *  book )
    {
       cout << "书标题  : " << book->title <<endl;
       cout << "书作者 : " << book->author <<endl;
       cout << "书类目 : " << book->subject <<endl;
       cout << "书 ID : " << book->book_id <<endl;
    }

b.const、&和指针地址

与define不同:define是宏定义,预处理阶段完成替换(如同字符串替换),不检查类型。

6、const、&和指针地址
 - 对象访问:obj.val,指针访问:p->val、或者 (*p).val;
 - const修饰指针
    int x=3; int const * p=&x; 
    //p=&y 正确:const*p是 别名的地址只读[不变],别名的值可以改变
    //*p=4 错误:别名的地址只读
        变量名         存储地址            存储内容
        x             &x                3
        p             &p[const*只读]     &x
    int x=3; int * const p=&x; 
    //p=&y 错误:const p是 别名不变,内容不可变
        变量名         存储地址            存储内容
        x             &x                3
        p             &p                &x[const只读]
    const int x=3; const int * const p=&x;
    //p=&y; p=4错误:别名只读、别名的地址也只读
        变量名         存储地址            存储内容
        x             &x                3[const只读]
        p             &p[const只读]      &x[const只读]
  - const修饰引用
    int x=3; int const & y=x; 
    //x=10 正确
    //y=20 错误:y的存储地址锁定,无法产生内容改变
        变量名         存储地址            存储内容
        x             &x                3
        y             &x[const只读]      -(暂无->>差异副本)
    这样定义则把 y 锁定到 x ,且无法定义副本改变
 - 注意内容锁定只读、还是指针或别名只读
    int x=3; int const * y=&x; 
    //*y=5 错误:y的指针锁定
        变量名         存储地址            存储内容
        x             &x                3
        y             &y[const只读]      &x
    这样同样把 y 锁定到 &x ,不变
    int const x=3;
    //int * y=&x 错误:x的值与地址在初始化后都只读,
    使用 int const * y=&x 或 int const * const z=&x

c.类的定义和使用

这里std::cout在引用<iostream>时使用 use namespace std;,注意命名空间。

//0.引用
#include <string>
#include "TV.cpp"

    //1. `从栈`实例化TV: 单个对象、对象数组
    TV tv;
    TV tv20[20];

    //2. `从堆`实例化TV: 单个对象、对象数组
    TV *t = new TV();
    TV *t20 = new TV[20];

    //3. 赋值,执行方法
    tv.type = 20;
    tv.name = "属性必须全值";
    tv.power();
    t->changeVol();
    for (int i = 0; i < 20; i++) {
        t20[i].type = i;
        t20[i].name = "属性必须全值";
        t20[i].power();
    }
    
    //4. `堆`不用清理:new => delete + null
    delete t;
    t = NULL;
    delete []t20;
    t20 = NULL;
    //5. 类定义与使用,必须在main()之前(否则至少先声明)
    Coordinate ct;
    ct.x = 11;
    ct.y = 33;
    ct.printX();
    ct.printY();
    Coordinate *p = new Coordinate();
    if (p == NULL){
        //xxx
        return 0;
    }
    p->x = 100;
    p->y = 200;
    p->printX();
    p->printY();
    delete p;
    p = NULL;

    //6. 字符串,定义与赋值
    std::string s1;
    std::string s2("Abc");
    std::string s3(s2); //使用副本初始化
    std::string s4(4, 'c'); //初始化字符的n个副本
    std::cout << s1 << "*" << s2 << "+" << s3 << "~" << s4 << std::endl;
    //6.1 字符串常用操作
    s1.empty(); //true or false
    s2.size(); //length
    s2[2]; //索引为2的字符
    s2 + s3; //拼接
    s2 = s3; //替换
    s2 == s3; //比较
    s2 != s3;

2、类构造指针和系统堆、自定义栈

a.类构造函数、生命周期

1、面向对象
- 类的操作方法必须在其内部实现,如:直接吃肉和使用餐具;
- 除方法外,其他变量、类定义后需要分号结束
2、类外定义
- 类的方法写在类定义的外面,至于直接分开为 xx.h、xx.cpp;
- 类内定义的函数优先选择编译为内联函数(inline修饰),在编译阶段直接替换
    (1)类内定义成员函数,可以不用在函数头部加inline关键字;
    (2)类外定义:inline void TV::power(){};
    (3)普通的宏定义函数:由预处理器对进行宏替代;
- 类文件调用,引用 class.cpp[内部引用class.h]
3、内存分区
- 栈区:存放变量类;                 [**自动管理**]
- 堆区:存放指针类;                 [手动管理]
- 全局区:存储全局变量、静态变量;
- 常量区:string str = "hello";
- 代码区:存放二进制代码;
4、构造函数
- 本名函数、没有类型修饰符,如果没有定义、系统自动定义空的
- 在类实例化时自动调用
- 重载
    class Student
    {
     public:
        Student(){m_strName = "Jim"}            //无参构造函数
        Student(string name){m_strName = name}  //重载
    };
- 列表赋值[构造函数初始化]
    class Student
    {
     public:
        Student():m_strName("Jim"),m_iAge(15){}  //此列表先于构造函数执行
    ...
    class Circle
    {
    public:
        Circle():m_dPi(3.14){}                  //常量初始化:Circle类,定义Π
    private:
        const double m_dPi;
        
    };
5、构造函数高级
- 拷贝构造函数:静态、类、引用变量,如果没有定义、系统自动定义空的
    class Student
    {
     public:
        Student(const Student &stu){}           //拷贝构造函数
    };
- 析构函数:对象销毁自动使用,无参、释放 new 的资源
    class Student
    {
     public:
        Student(const Student &stu){}           //拷贝构造函数
        ~Student(){}                            //析构函数
    };
- 对象生命历程:申请内存 - 初始化列表 - 构造函数 - 参与运算 - 析构函数 - 释放内存

b.类的指针,文件引用

1、类的构造引用
- &和指针运算
    Coordinate coord[3];                    //栈实例化,自动回收
    coord[1].m_iX = 10;
    Coordinate * p = new Coordinate[3];     //堆实例化
    p[0].m_iY = 10;
    p[1].m_iY = 111;
    p[2].m_iY = 2282;
    p->m_iY = 30; //覆盖p[0].m_iY            //指针变量p的++相当于移位
    cout << & (p[0]) << "\t" << & (p[1]) << "\t" << & (p[2]) << "\t" << & (p[3]) << endl;
    cout << p++ << "\t" << p++ << "\t" << p++ << "\t" << p << endl; //结果同上,移位、下面不同
    cout << & (p[0]) << "\t" << & (p[1]) << "\t" << & (p[2]) << "\t" << & (p[3]) << endl;
    cout << p->m_iY << ", " << p[1].m_iY << endl; //随机数, 0

    cout << --p << "\t" << --p << "\t" << --p << "\t" << p << endl; //指针复位,逆序输出
    cout << p->m_iY << ", " << p[1].m_iY << endl
- 头部引用关联:属性头类、操作方法、主文件
    关联实例:主类 + 线段类 + 坐标类
    main_line.cpp
        include "libs/Line.h";
        
    libs/Line.cpp
        include "Line.h";
    libs/Line.h
        include "Coordinate.h";
        
    libs/Coordinate.cpp
        include "Coordinate.h";
    libs/Coordinate.h
        -
    a.主函数内引用xx.cpp或xx.h等效(编译工作),目前注意不要重复引用:"不重复"、<系统的方括号正常调用>,
    b.操作方法xx.cpp调用属性头xx.h,
    c.属性头类xx.h引用其它类,使用xx.cpp或xx.h,
    d.列表赋值只定义一次 Line(int x1, int y1, int x2, int y2):pointA(x1,y1),pointB(x2,y2) {},建议放到操作方法中;
- 堆区销毁:[栈(数据结构):一种先进后出的数据结构]
    Coordinate all init 1, 2
    Coordinate all init 3, 4
    Line all init
    (1, 2) => (3, 4)
    ~ Line destory
    ~ Coordinate destory 3, 4
    ~ Coordinate destory 1, 2
- 浅拷贝、深拷贝:注意在有指针的对象拷贝时、重新分配空间,否则造成多次释放;

c.this、类的生命周期,常引用、常指针

1、this、类的生命周期,常引用、常指针
- this是对象的一个特殊的指针:Obj obj; this == & obj ;
    Obj obj(10) ==> Obj obj(this, 10)
    系统不会在多个对象错乱的情况,是为每个成员函数自动加了this指针;
- 对象生命周期[系统栈 分配空间]
    Coordinate init (1, 2)
    Coordinate init (3, 4)
    Line (1, 2) => (3, 4) INIT ...
    (1, 2) => (3, 4)
    =====================
    Coordinate init (11, 22)
    Coordinate init (33, 44)
    Line (11, 22) => (33, 44) INIT ...
    const (11, 22) => (33, 44)

    ~ Line (11, 22) => (33, 44) DELETE
    ~ Coordinate destory 33, 44
    ~ Coordinate destory 11, 22
    ~ Line (1, 2) => (3, 4) DELETE
    ~ Coordinate destory 3, 4
    ~ Coordinate destory 1, 2
- 对象的常指针、常引用二,note1.txt继
    //虚拟系统 this 首参的编译器工作:如果有内部函数、属性调用则自动进行[以区分位于不同对象]
    a.const修饰*[指向]&[引用]符号时:[变量的:名-址-值 >>值不变]
    CoordinateX coor(3,5);
    const CoordinateX & coor2 = coor; // &coor2锁定 => coor锁定,coor2的内容锁定、可以有多个coor2定义
    const CoordinateX * pCoor = & coor; // *pCoor锁定 => pCoor的地址不变、值可变,coor地址不可变、值可变
    cout << "& coor2: " << &coor2 << "; * pCoor: " << pCoor << endl;
    coor.info();
    coor.setX(33); //coor地址不可变、值可变
    cout << coor.getX() << endl;
    //coor2.getY(); // error: 将'const CoordinateX'作为'this'参数丢弃限定词
    //pCoor->getX(); // error: 同上
    //coor2,pCoor set更不可能
    CoordinateX coorP(22,33);
    pCoor = & coorP; //pCoor的地址不变、值可变

    b.const修饰变量时:[变量的:名-址-值 >>值不变]
    CoordinateX door(3,5);
    //CoordinateX & const door2 = door; // error: 'const'限定符不能应用于'CoordinateX&',[coor2无内容不可锁定]
    CoordinateX * const pDoor = & door; // pCoor锁定 => pCoor指向[指针内容]不可变,coor1地址不可变、值可变
    coor.info();
    coor.setY(55);
    cout << door.getY() << endl;
    CoordinateX doorP(22,33);
    //pDoor = & doorP; //error: 分配只读变量“pDoor”,[pCoor指向||指针内容不可变]
    pDoor->setX(66);
    cout << door.getX() << endl; //pDoor -> door

实例代码上传:
https://github.com/cffycls/cplus2


沧浪水
97 声望12 粉丝