Unit03: 类的定义与实例化 、 构造函数与初始化表 、 this指针与常函数

c & cpp

九、 C++ 的引用 ( reference )

  1. 定义引用就是给某个变量起别名, 对引用的操作与对该变量的操作完全相同.

  2. 常引用
    1) 定义引用的时候加 const 修饰, 即为常引用, 不能通过常引用修改引用的目标
    2) 普通的引用只能是左值(变量), 常引用也叫万能引用,即可以引用左值也可以引用右值.

  3. 关于左值和右值的概念
    1) 左值: 可以放在运算符左边,可以被修改,可以被取地址
    2) 右值: 只能放在赋值运算符右边, 不可以被修改, 不可以被取地址

  4. 引用型的参数
    1) 可以将引用用于函数的参数,可以直接修改实参变量的值,同时可以减少函数调用的开销
    2) 引用参数有可能意外的修改实参变量的值,如果不希望修改实参本身,可以将行参定义为常引用,在提高传参效率的同时还可以接收常量型的实参

  5. 引用型函数的返回值
    1) 可以将函数的返回类型声明为引用,避免函数返回值带来的内存开销,如果一个函数的返回类型被声明为引用,那么该函数返回值可能是一个左值.
    2) 为了避免在函数外部修改引用目标的变量,可以返回一个常引用.

        int g_data = 100;
        int& func(void){
            g_data = 200;
            return g_data;
        }
        int main(void){
            func() = 300; // ok --> g_data = 300
        }
  6. 引用和指针
    1) 引用的本质就是指针,但是建议尽量使用引用而不是指针.

        double d = 1.23;
        double& rd = d;
        double* const pd = &d;
        rd = 100; // ==> *pd = 100

    2) 指针可以不初始化,指针指向的目标可以随意改变(除了指针常量),而引用必须初始化,初始化以后目标不能修改

        int a, b;
        int* p; // ok
        p = &a; // p --> a
        p = &b; // p --> b
        /*错误*/int& r; // error
        int& r = a; // r 引用 a
        r = b; // 把 b 的值赋值给 a;

    3) 可以定义指针的指针(二级指针),但是不能定义引用的指针

        int a = 100;
        int* p = &a;
        int** pp = &p; // ok
        int& r = a;
        /*错误*/int&* pr = &r; // error

    4) 可以定义指针的引用,但是不能定义引用的引用

        int a;
        int* p = &a;
        int*& rp = p; // ok
        int& r = a;
        /*错误*/int&& rr = r; // error, c++11右值引用
5) 可以定义指针数组,但是不能定义引用数组,可以定义数组引用

eg:

        int a, b, c;
        int* parr[3] = {&a, &b, &c};
        /*错误*/int& rarr[3] = {a, b, c}; // error

eg 2:

        int arr[3] = {1, 2, 3};
        int (&r)[3] = arr; // ok

6) 函数指针和函数引用的语法基本一样

    void func(int a, double d){}
    int main(void){
        // 函数指针
        void (*pfunc)(int, double) = func;
        pfunc(100, 3.14);
        // 函数引用
        void (&rfunc)(int, double) = func;
        rfunc(200, 4.13);           
    }

十、c++ 动态内存分配

对比:
c 语言: malloc() / free()
c++: new / delete 运算符
new 运算符用于分配内存, delete 运算符用于释放内存
eg:
c:

    int* = (int*)malloc(4);
    *p = 100;
    free(p);
    p = NULL;

c++

    // int* = new int;
    // *p = 200;    
    int* = new int(200); // 分配内存同时初始化
    delete p;
    p = NULL;

        int* pa = new int[10]; // 分配 10 个 int 空间
        pa[0] = 10;
        pa[1] = 20;
        // ...
        delete[] = pa;
        pa = NULL;

十一、类型转换

  1. 隐式类型转换
        char c = 'A';
        int i = c; // 隐式转换
        int foo(int n){
            char ch = 'A';
            return ch; // 隐式转换
        }
        int main(void){
            foo('A'); // 隐式转换
        }
  1. 显示类型转换
    2.1 c 语言 显式类型转换(强制类型转换)

    // 内存地址: 0x12345678
    
    int* pi = (int*)0x12345678;
    *pi = 100;
    char c = 'A';
    int i = (int)c; // c 中形式
    int i = int(c); // c++ 中形式
    int* pc = (int*)c; // 语法 ok, 逻辑不合理

    2.2 c++ 兼容 c 的强制转换, 同时增加了四种操作符的形式
    1) 静态类型转换
    目标类型变量 = static_case<目标类型>(源类型变量);
    主要用于将 void* 转换为其他类型的指针

                int a = 100;
                void* pv = &a; // int* -> void*
                int* pi = static_cast<int*>(pv); // ok
    
                double d = 3.14;
                /*错误*/pi = static_cast<int*>(&d); // 逻辑不合理, error    

    2) 动态类型转换
    目标类型变量 = dynamic_cast<目标类型>(源类型变量);

    3) 常类型转换
    目标类型变量 = const_cast<目标类型>(源类型变量);
    用于去除一个指针或者引用的常属性.

    int main(void){
                    int a = 100;
                    const int* = &a;
                    // *p =  20; // error
                    int* p2 = const_cast<int*>(p);

                    const int& r = a;
                    /*错误*/r = 30; // error
                    int& r2 = const_cast<int&>(r);
                    r2 = 30; // ok
                }  
4) 重解释类型转换
目标类型变量 = reinterpret_cast<目标类型>(源类型变量);
--> 任意类型指针或引用之间的转换
--> 在指针和整形数之间的转换
    int a;
    int* pa = &a;
    double* pd = reinterpret_cast<double*>(pa);
    // eg 2:
    // 向内存"ox23e00000"存放数据100
        // c
        *((int*)0x23e00000) = 100;
        // c++
        int p = 0x23e00000;
        int* paddr = reinterpret_cast<int*>(p);
        *paddr = 100;
c++ 编程的几点小建议:
1. 慎用宏
    #define PAI 3.14    ==> const double PAI = 3.14;
    #define STATE_SLEEP 0
    #define STATE_RUN 1
    #define STATE_STOP 2
    // ==> 
    enum STATE{SLEEP, RUN, STOP}

        #define max(a, b)((a) > (b) ? (a) : (b))
        // ==>
        inline int max(int a, int b){
            return a > b ? a : b;
        }
2.  变量随用随声明同时初始化
3.   尽量使用 new / delete 取代 malloc / free
4.  少用 void* , 指针计算、联合体、强制转换
5.  尽量用 string 表示字符串, 少用 c 风格的 char*

十二、类和对象

  1. 对象
    万物皆对象, 任何一种事物都可以看做是一个对象

  2. 面向对象
    2.1 如何描述和表达对象
    通过对象的属性(名词、数量词、形容词)和行为(动词)来描述和表达对象.
    “冰箱”
    冰箱属性: 品牌、容量、颜色、功耗
    冰箱的行为: 装东西、冷冻、冷藏
    2.2 面向对象程序设计
    对自然世界的观察引入到编程实践的一种理念和方法;
    数据抽象: 在描述对象时, 把细节东西剥离出去, 只考虑一般性的、有规律的、统一的东西.


  3. 类是将多个对象的共性提取出来定义的一种新的数据类型,是对对象的属性和行为的抽象描述,对象是类的实例化.
    学生:
    现实世界 类 虚拟世界(编程模拟)
    具体对象 – 抽象 –> 属性 / 行为 – 实例化 –> 具体对象

    struct Student{
            string name;
            int age;
            int id;
            void eat( ){
            }
            void sleep( ){
            }
        }
        Student s;
        s.name = "Leon";
        s.age = 25;
        s.id = 10010;
        s.eat();

十三、类的定义和实例化

  1. 类的语法形式
    class / struct 类型 : 继承表{
    访问控制限定符:
    类名(行参表) : 初始化{} // 构造函数
    ~类名(void){ }// 析构函数
    返回类型 函数名(行参表){ } // 成员函数
    数据类型 变量名; // 成员变量
    };

  2. 访问控制限定符
    public: 公有成员, 在类的内部和外部都可以访问的成员
    private: 私有成员, 只有在类的内部才能访问
    protected: 保护成员
    注: class 定义的类默认的访问控制属性为 private, 而 struct 定义的类默认访问属性为 public

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡德咏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值