2024年3月

实例:

// 定义类
class Circle {
public:
    int m_r; // 规范:属性要加m_表示成员属性
    double caculateZC() {
        return 2 * PI * m_r;
    }
}; // 区别于JAVA,要有;

// 使用栈区创建和使用对象的方式,作用域为函数内,函数返回前自动执行对象的析构函数
Circle circle;
circle.m_r = 10;
double l = circle.caculateZC();

函数默认参数

C++有这个特性,JAVA没有

int func(int a, int b = 10, int c = 20) {
    return a+b+c;
}

声明和实现只能有一个默认参数

//正确的书写
int func(int, int, int);
int func(int a, int b = 10, int c = 20) {
    return a+b+c;
}

//正确的书写
int func(int a, int b, int c);
int func(int a, int b = 10, int c = 20) {
    return a+b+c;
}

//错误的书写
int func(int a, int b = 10, int c = 20);
int func(int a, int b = 10, int c = 20) {
    return a+b+c;
}

//错误的书写
int func(int a, int b = 1, int c = 2);
int func(int a, int b = 10, int c = 20) {
    return a+b+c;
}

引用作为重载的条件

void func(int &a) { // int &a = 10; // 不合法,引用变量必须赋初值且指向一处内存空间
    cout << "void func(int &a)被调用" << endl;
}

void func(const int &a) { // 只读,所以func(a)没有func(10)适配
    cout << "void func(const int &a)被调用" << endl;
}

int a = 10;
func(a); // void func(int &a)被调用
func(10); // void func(const int &a)被调用

引用本质上是指针常量

&、*的四种修饰情况:

int a = 1;
int *p = &a; // 定义变量时修饰*,定义指针;使用变量时修饰&,取地址
int &b = a; // 定义变量时修饰&为引用,即取别名
cout << *p << endl; // 使用变量时用*为取值,即a的值1

函数的返回值可以是引用类型

int & func() {
    static int a = 1;
    return a;
}

int b = func();
func() = 2;
cout << b << endl; // b=2

常量引用
作用:修饰形参,可以防止误操作;常量引用结合了常量和引用的优势,既保证值不被修改(常量的优势),也节省了空间(引用的优势)——因为引用本质是指针常量,即不能改变指针指向,指针的优势是只要存储一个地址,当需要传递一个很大的结构体时只需传递结构体的地址而不需要将整个结构体都复制一遍。

const int & ref = 10; // 等价于int temp = 10; const int & ref = temp;
int & a = 10; // 但这种操作不允许,引用一定要引一块合法的内存空间
ref = 20; // 报错,常量引用不能修改

void func(const int & val) {
    val = 10; // 报错,常量引用不能修改
}

在堆区开辟内存的几种方式

  1. malloc函数

    #include <malloc.h>
    int * p = (int *)malloc(sizeof(int) * 10);
  2. new关键字创建数、数组,仅C++

    int * func() {
     int * p = new int[10]; // 用指针接收new出来的堆区空间
     int * q = new int(10); // 区别于上行,这行只创建一个int型变量
     delete q; // 释放q指向的堆区数据
     return p;
    }
    void test() {
     int * p = func();
     delete [] p; // 释放p指向的堆区数据,注意释放数组的写法里有中括号
    }

空指针

int * p = NULL; // #define NULL 0
int * p = nullptr; // #define nullptr 0

野指针

int * p = (int *)0x3030; // 尽量避免这种写法

const修饰指针

  1. 常量指针(const修饰int,修饰的是值):指针的指向可以修改,但指针指向的值不能改

    int a = 10, b = 10;
    const int * p = &a;
    p = &b; // 正常执行
    *p = 20; // 报错
  2. 指针常量(const修饰p,修饰的是指针):指针的指向不能改,指针指向的值可以改

    int a = 10, b = 10;
    int * const p = &a;
    p = &b; // 报错
    *p = 20; // 正常执行
  3. const既修饰常量,也修饰指针

    int a = 10, b = 10;
    const int * const p = &a;
    p = &b; // 报错
    *p = 20; // 报错

const修饰形参,防止误改

struct Obj{
    int value = 0;
}
void f(const Obj * obj) {
    obj->value = 10; // 报错